diff --git a/rts/Menu/SelectMenu.cpp b/rts/Menu/SelectMenu.cpp index 72cd95667d..c2949faf9e 100644 --- a/rts/Menu/SelectMenu.cpp +++ b/rts/Menu/SelectMenu.cpp @@ -57,26 +57,26 @@ class ConnectWindow : public agui::Window { HorizontalLayout* input = new HorizontalLayout(wndLayout); /*agui::TextElement* label = */new agui::TextElement("Address:", input); // will be deleted in input address = new agui::LineEdit(input); - address->DefaultAction.connect(std::bind(&ConnectWindow::Finish, this, true)); + address->DefaultAction = std::bind(&ConnectWindow::Finish, this, true); address->SetFocus(true); address->SetContent(configHandler->GetString("address")); HorizontalLayout* buttons = new HorizontalLayout(wndLayout); Button* connect = new Button("Connect", buttons); - connect->Clicked.connect(std::bind(&ConnectWindow::Finish, this, true)); + connect->Clicked = std::bind(&ConnectWindow::Finish, this, true); Button* close = new Button("Close", buttons); - close->Clicked.connect(std::bind(&ConnectWindow::Finish, this, false)); + close->Clicked = std::bind(&ConnectWindow::Finish, this, false); GeometryChange(); } - slimsig::signal Connect; + OnClickStringType Connect; agui::LineEdit* address; private: void Finish(bool connect) { if (connect) - Connect.emit(address->GetContent()); + Connect(address->GetContent()); else - WantClose.emit(); + WantClose(); }; }; @@ -91,27 +91,27 @@ class SettingsWindow : public agui::Window { HorizontalLayout* input = new HorizontalLayout(wndLayout); /*agui::TextElement* value_label = */new agui::TextElement("Value:", input); // will be deleted in input value = new agui::LineEdit(input); - value->DefaultAction.connect(std::bind(&SettingsWindow::Finish, this, true)); + value->DefaultAction = std::bind(&SettingsWindow::Finish, this, true); value->SetFocus(true); if (configHandler->IsSet(name)) value->SetContent(configHandler->GetString(name)); HorizontalLayout* buttons = new HorizontalLayout(wndLayout); Button* ok = new Button("OK", buttons); - ok->Clicked.connect(std::bind(&SettingsWindow::Finish, this, true)); + ok->Clicked = std::bind(&SettingsWindow::Finish, this, true); Button* close = new Button("Cancel", buttons); - close->Clicked.connect(std::bind(&SettingsWindow::Finish, this, false)); + close->Clicked = std::bind(&SettingsWindow::Finish, this, false); GeometryChange(); } - slimsig::signal OK; + OnClickStringType OK; agui::LineEdit* value; private: void Finish(bool set) { if (set) - OK.emit(title + " = " + value->GetContent()); + OK(title + " = " + value->GetContent()); else - WantClose.emit(); + WantClose(); }; }; @@ -152,23 +152,23 @@ SelectMenu::SelectMenu(std::shared_ptr setup) menu->SetBorder(1.2f); /*agui::TextElement* title = */new agui::TextElement("Spring " + SpringVersion::GetFull(), menu); // will be deleted in menu Button* testGame = new Button("Test Game", menu); - testGame->Clicked.connect(std::bind(&SelectMenu::Single, this)); + testGame->Clicked = std::bind(&SelectMenu::Single, this); Button* playDemo = new Button("Play Demo", menu); - playDemo->Clicked.connect(std::bind(&SelectMenu::Demo, this)); + playDemo->Clicked = std::bind(&SelectMenu::Demo, this); Button* loadGame = new Button("Load Game", menu); - loadGame->Clicked.connect(std::bind(&SelectMenu::Load, this)); + loadGame->Clicked = std::bind(&SelectMenu::Load, this); userSetting = configHandler->GetString("LastSelectedSetting"); Button* editsettings = new Button("Edit Settings", menu); - editsettings->Clicked.connect(std::bind(&SelectMenu::ShowSettingsList, this)); + editsettings->Clicked = std::bind(&SelectMenu::ShowSettingsList, this); Button* directConnect = new Button("Direct Connect", menu); - directConnect->Clicked.connect(std::bind(&SelectMenu::ShowConnectWindow, this, true)); + directConnect->Clicked = std::bind(&SelectMenu::ShowConnectWindow, this, true); Button* quit = new Button("Quit", menu); - quit->Clicked.connect(std::bind(&SelectMenu::Quit, this)); + quit->Clicked = std::bind(&SelectMenu::Quit, this); background->GeometryChange(); } @@ -273,8 +273,8 @@ void SelectMenu::ShowConnectWindow(bool show) if (show && !conWindow) { conWindow = new ConnectWindow(); - conWindow->Connect.connect(std::bind(&SelectMenu::DirectConnect, this, std::placeholders::_1)); - conWindow->WantClose.connect(std::bind(&SelectMenu::ShowConnectWindow, this, false)); + conWindow->Connect = (std::bind(&SelectMenu::DirectConnect, this, std::placeholders::_1)); + conWindow->WantClose = std::bind(&SelectMenu::ShowConnectWindow, this, false); } else if (!show && conWindow) { @@ -291,8 +291,8 @@ void SelectMenu::ShowSettingsWindow(bool show, std::string name) settingsWindow = nullptr; } settingsWindow = new SettingsWindow(name); - settingsWindow->OK.connect(std::bind(&SelectMenu::ShowSettingsWindow, this, false, std::placeholders::_1)); - settingsWindow->WantClose.connect(std::bind(&SelectMenu::ShowSettingsWindow, this, false, "")); + settingsWindow->OK = std::bind(&SelectMenu::ShowSettingsWindow, this, false, std::placeholders::_1); + settingsWindow->WantClose = std::bind(&SelectMenu::ShowSettingsWindow, this, false, ""); } else if (!show && settingsWindow) { agui::gui->RmElement(settingsWindow); @@ -311,8 +311,8 @@ void SelectMenu::ShowSettingsList() { if (curSelect == nullptr) { curSelect = new ListSelectWnd("Select setting"); - curSelect->Selected.connect(std::bind(&SelectMenu::SelectSetting, this, std::placeholders::_1)); - curSelect->WantClose.connect(std::bind(&SelectMenu::CleanWindow, this)); + curSelect->Selected = std::bind(&SelectMenu::SelectSetting, this, std::placeholders::_1); + curSelect->WantClose = std::bind(&SelectMenu::CleanWindow, this); } curSelect->list->RemoveAllItems(); diff --git a/rts/Menu/SelectionWidget.cpp b/rts/Menu/SelectionWidget.cpp index ce9ab96162..04e5d78ddc 100644 --- a/rts/Menu/SelectionWidget.cpp +++ b/rts/Menu/SelectionWidget.cpp @@ -54,7 +54,7 @@ SelectionWidget::SelectionWidget(agui::GuiElement* parent) : agui::GuiElement(pa agui::HorizontalLayout* modL = new agui::HorizontalLayout(vl); mod = new agui::Button("Select", modL); - mod->Clicked.connect(std::bind(&SelectionWidget::ShowModList, this)); + mod->Clicked = std::bind(&SelectionWidget::ShowModList, this); mod->SetSize(0.1f, 0.00f, true); userDemo = NoDemoSelect; @@ -70,12 +70,12 @@ SelectionWidget::SelectionWidget(agui::GuiElement* parent) : agui::GuiElement(pa agui::HorizontalLayout* mapL = new agui::HorizontalLayout(vl); map = new agui::Button("Select", mapL); - map->Clicked.connect(std::bind(&SelectionWidget::ShowMapList, this)); + map->Clicked = std::bind(&SelectionWidget::ShowMapList, this); map->SetSize(0.1f, 0.00f, true); agui::HorizontalLayout* scriptL = new agui::HorizontalLayout(vl); script = new agui::Button("Select", scriptL); - script->Clicked.connect(std::bind(&SelectionWidget::ShowScriptList, this)); + script->Clicked = std::bind(&SelectionWidget::ShowScriptList, this); script->SetSize(0.1f, 0.00f, true); modT = new agui::TextElement(userMod, modL); @@ -97,8 +97,8 @@ void SelectionWidget::ShowDemoList(const std::function return; curSelect = new ListSelectWnd("Select demo"); - curSelect->Selected.connect(std::bind(&SelectionWidget::SelectDemo, this, std::placeholders::_1)); - curSelect->WantClose.connect(std::bind(&SelectionWidget::CleanWindow, this)); + curSelect->Selected = std::bind(&SelectionWidget::SelectDemo, this, std::placeholders::_1); + curSelect->WantClose = std::bind(&SelectionWidget::CleanWindow, this); const std::string cwd = FileSystem::EnsurePathSepAtEnd(FileSystemAbstraction::GetCwd()); const std::string dir = FileSystem::EnsurePathSepAtEnd("demos"); @@ -117,8 +117,8 @@ void SelectionWidget::ShowSavegameList(const std::functionSelected.connect(std::bind(&SelectionWidget::SelectSavegame, this, std::placeholders::_1)); - curSelect->WantClose.connect(std::bind(&SelectionWidget::CleanWindow, this)); + curSelect->Selected = std::bind(&SelectionWidget::SelectSavegame, this, std::placeholders::_1); + curSelect->WantClose = std::bind(&SelectionWidget::CleanWindow, this); const std::string cwd = FileSystem::EnsurePathSepAtEnd(FileSystemAbstraction::GetCwd()); const std::string dir = FileSystem::EnsurePathSepAtEnd("Saves"); @@ -151,8 +151,8 @@ void SelectionWidget::ShowModList() return; curSelect = new ListSelectWnd("Select game"); - curSelect->Selected.connect(std::bind(&SelectionWidget::SelectMod, this, std::placeholders::_1)); - curSelect->WantClose.connect(std::bind(&SelectionWidget::CleanWindow, this)); + curSelect->Selected = std::bind(&SelectionWidget::SelectMod, this, std::placeholders::_1); + curSelect->WantClose = std::bind(&SelectionWidget::CleanWindow, this); std::vector found = archiveScanner->GetPrimaryMods(); std::sort(found.begin(), found.end(), [](const CArchiveScanner::ArchiveData& a, const CArchiveScanner::ArchiveData& b) { @@ -172,8 +172,8 @@ void SelectionWidget::ShowMapList() return; curSelect = new ListSelectWnd("Select map"); - curSelect->Selected.connect(std::bind(&SelectionWidget::SelectMap, this, std::placeholders::_1)); - curSelect->WantClose.connect(std::bind(&SelectionWidget::CleanWindow, this)); + curSelect->Selected = std::bind(&SelectionWidget::SelectMap, this, std::placeholders::_1); + curSelect->WantClose = std::bind(&SelectionWidget::CleanWindow, this); std::vector arFound = archiveScanner->GetMaps(); std::sort(arFound.begin(), arFound.end(), doj::alphanum_less()); @@ -243,8 +243,8 @@ void SelectionWidget::ShowScriptList() return; curSelect = new ListSelectWnd("Select script"); - curSelect->Selected.connect(std::bind(&SelectionWidget::SelectScript, this, std::placeholders::_1)); - curSelect->WantClose.connect(std::bind(&SelectionWidget::CleanWindow, this)); + curSelect->Selected = std::bind(&SelectionWidget::SelectScript, this, std::placeholders::_1); + curSelect->WantClose = std::bind(&SelectionWidget::CleanWindow, this); for (const std::string& scriptName: availableScripts) { curSelect->list->AddItem(scriptName, ""); diff --git a/rts/Menu/SelectionWidget.h b/rts/Menu/SelectionWidget.h index dbebdd8b5c..a3ce878d71 100644 --- a/rts/Menu/SelectionWidget.h +++ b/rts/Menu/SelectionWidget.h @@ -34,28 +34,28 @@ class ListSelectWnd : public agui::Window agui::VerticalLayout* modWindowLayout = new agui::VerticalLayout(this); list = new agui::List(modWindowLayout); - list->FinishSelection.connect(std::bind(&ListSelectWnd::SelectButton, this)); + list->FinishSelection = std::bind(&ListSelectWnd::SelectButton, this); agui::HorizontalLayout* buttons = new agui::HorizontalLayout(modWindowLayout); buttons->SetSize(0.0f, 0.04f, true); agui::Button* select = new agui::Button("Select", buttons); - select->Clicked.connect(std::bind(&ListSelectWnd::SelectButton, this)); + select->Clicked = std::bind(&ListSelectWnd::SelectButton, this); agui::Button* cancel = new agui::Button("Close", buttons); - cancel->Clicked.connect(std::bind(&ListSelectWnd::CancelButton, this)); + cancel->Clicked = std::bind(&ListSelectWnd::CancelButton, this); GeometryChange(); } - slimsig::signal Selected; + OnClickStringType Selected; agui::List* list; private: void SelectButton() { list->SetFocus(false); - Selected.emit(list->GetCurrentItem()); + Selected(list->GetCurrentItem()); } void CancelButton() { - WantClose.emit(); + WantClose(); } }; diff --git a/rts/Rml/Backends/RmlUi_Backend.cpp b/rts/Rml/Backends/RmlUi_Backend.cpp index 12fbdd2eaf..8d37b1948b 100644 --- a/rts/Rml/Backends/RmlUi_Backend.cpp +++ b/rts/Rml/Backends/RmlUi_Backend.cpp @@ -102,7 +102,7 @@ class BackendState : public Rml::Plugin { Rml::Context* debug_host_context = nullptr; Rml::Context* clicked_context = nullptr; - InputHandler::SignalType::connection_type inputCon; + InputHandler::HandlerTokenT inputCon; CRmlInputReceiver inputReceiver; bool initialized = false; diff --git a/rts/System/Input/InputHandler.cpp b/rts/System/Input/InputHandler.cpp index 878197f21d..3ca8037aee 100644 --- a/rts/System/Input/InputHandler.cpp +++ b/rts/System/Input/InputHandler.cpp @@ -9,7 +9,12 @@ InputHandler::InputHandler() = default; void InputHandler::PushEvent(const SDL_Event& ev) { - sig.emit(ev); + for (const auto& eventHandler : eventHandlers) { + if (eventHandler) { + if (eventHandler(ev)) + break; + } + } } void InputHandler::PushEvents() @@ -25,8 +30,16 @@ void InputHandler::PushEvents() } } - -InputHandler::SignalType::connection_type InputHandler::AddHandler(SignalType::callback handler) +InputHandler::HandlerTokenT InputHandler::AddHandler(InputHandler::HandlerFuncT func) { - return sig.connect(handler); + for (size_t i = 0; i < eventHandlers.size(); ++i) { + if (eventHandlers[i] == nullptr) { + eventHandlers[i] = func; + return InputHandler::HandlerTokenT{ *this, i}; + } + } + eventHandlers.emplace_back(func); + return InputHandler::HandlerTokenT{ *this, eventHandlers.size() - 1 }; } + + diff --git a/rts/System/Input/InputHandler.h b/rts/System/Input/InputHandler.h index b501091513..394f63a8b3 100644 --- a/rts/System/Input/InputHandler.h +++ b/rts/System/Input/InputHandler.h @@ -3,7 +3,8 @@ #ifndef INPUT_HANDLER_H #define INPUT_HANDLER_H -#include +#include +#include #include /** @@ -13,17 +14,48 @@ class InputHandler { public: - typedef slimsig::signal SignalType; + class HandlerTokenT { + public: + friend class InputHandler; + constexpr HandlerTokenT() + : ih(nullptr) + , pos(0) + {} + HandlerTokenT(InputHandler& ih_, size_t pos_) + : ih(&ih_) + , pos(pos_) + {} + HandlerTokenT(const HandlerTokenT&) = delete; + HandlerTokenT(HandlerTokenT&& other) noexcept { *this = std::move(other); } + ~HandlerTokenT() + { + if (ih) { + ih->eventHandlers[pos] = nullptr; + } + } + + HandlerTokenT& operator=(const HandlerTokenT&) = delete; + HandlerTokenT& operator=(HandlerTokenT&& other) noexcept { + std::swap(ih, other.ih); + std::swap(pos, other.pos); + + return *this; + } + private: + InputHandler* ih; + size_t pos; + }; +public: + using HandlerFuncT = std::function; InputHandler(); void PushEvent(const SDL_Event& ev); void PushEvents(); - SignalType::connection_type AddHandler(SignalType::callback); - + HandlerTokenT AddHandler(HandlerFuncT func); private: - SignalType sig; + std::vector eventHandlers; }; extern InputHandler input; diff --git a/rts/System/Input/MouseInput.cpp b/rts/System/Input/MouseInput.cpp index 5d721df9aa..c7fbed6708 100644 --- a/rts/System/Input/MouseInput.cpp +++ b/rts/System/Input/MouseInput.cpp @@ -27,8 +27,6 @@ #include "System/MainDefines.h" #include "System/SafeUtil.h" -#include - #include #include #include @@ -36,10 +34,9 @@ IMouseInput* mouseInput = nullptr; - IMouseInput::IMouseInput(bool relModeWarp) { - inputCon = input.AddHandler(std::bind(&IMouseInput::HandleSDLMouseEvent, this, std::placeholders::_1)); + inputCon = input.AddHandler([this](const SDL_Event& event) { return this->HandleSDLMouseEvent(event); }); #ifndef HEADLESS // Windows 10 FCU (Fall Creators Update) causes spurious SDL_MOUSEMOTION // events to be generated with SDL_HINT_MOUSE_RELATIVE_MODE_WARP enabled @@ -62,7 +59,6 @@ IMouseInput::~IMouseInput() #ifndef HEADLESS SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "0"); #endif - inputCon.disconnect(); } diff --git a/rts/System/Input/MouseInput.h b/rts/System/Input/MouseInput.h index 51cef92ba8..cb96131552 100644 --- a/rts/System/Input/MouseInput.h +++ b/rts/System/Input/MouseInput.h @@ -4,7 +4,6 @@ #define MOUSE_INPUT_H #include -#include #include "System/Input/InputHandler.h" #include "System/type2.h" @@ -33,7 +32,7 @@ class IMouseInput protected: int2 mousepos; - InputHandler::SignalType::connection_type inputCon; + InputHandler::HandlerTokenT inputCon; }; extern IMouseInput* mouseInput; diff --git a/rts/System/SpringApp.cpp b/rts/System/SpringApp.cpp index 1597bbef76..76556c4b3b 100644 --- a/rts/System/SpringApp.cpp +++ b/rts/System/SpringApp.cpp @@ -1,7 +1,5 @@ /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ -#include "System/Input/InputHandler.h" - #include #include #include @@ -272,7 +270,7 @@ bool SpringApp::Init() CInfoConsole::InitStatic(); CMouseHandler::InitStatic(); - input.AddHandler(std::bind(&SpringApp::MainEventHandler, this, std::placeholders::_1)); + inputToken = input.AddHandler([this](const SDL_Event& event) { return SpringApp::MainEventHandler(event); }); // Global structures gs->Init(); diff --git a/rts/System/SpringApp.h b/rts/System/SpringApp.h index 63597206da..0378a40d98 100644 --- a/rts/System/SpringApp.h +++ b/rts/System/SpringApp.h @@ -7,6 +7,7 @@ #include #include "System/Log/ConsoleSink.h" +#include "System/Input/InputHandler.h" class ClientSetup; class CGameController; @@ -68,6 +69,8 @@ class SpringApp /* Member instead of global to avoid catching unrelated early messages. * In particular, modes like `spring -p` want a clean output log without library chaff. */ ConsoleSinkRegistrator consoleSink; + + InputHandler::HandlerTokenT inputToken; }; /** diff --git a/rts/aGui/Button.cpp b/rts/aGui/Button.cpp index aaffcb260e..2296ba323e 100644 --- a/rts/aGui/Button.cpp +++ b/rts/aGui/Button.cpp @@ -74,8 +74,8 @@ bool Button::HandleEventSelf(const SDL_Event& ev) && MouseOver(ev.button.x, ev.button.y) && clicked) { - if (!Clicked.empty()) { - Clicked.emit(); + if (Clicked) { + Clicked(); } else { LOG_L(L_WARNING, "Button %s clicked without callback", label.c_str()); } diff --git a/rts/aGui/Button.h b/rts/aGui/Button.h index 2251fe0f47..2484d18d82 100644 --- a/rts/aGui/Button.h +++ b/rts/aGui/Button.h @@ -4,7 +4,6 @@ #define BUTTON_H #include -#include #include "GuiElement.h" @@ -18,7 +17,7 @@ class Button : public GuiElement void Label(const std::string& label); - slimsig::signal Clicked; + OnClickVoidType Clicked; private: virtual void DrawSelf(); diff --git a/rts/aGui/Gui.cpp b/rts/aGui/Gui.cpp index 6d210d87ac..d5f888f7c1 100644 --- a/rts/aGui/Gui.cpp +++ b/rts/aGui/Gui.cpp @@ -3,7 +3,6 @@ #include "System/Input/InputHandler.h" #include "Gui.h" -#include #include #include "GuiElement.h" @@ -17,7 +16,7 @@ namespace agui Gui::Gui() { - inputCon = input.AddHandler(std::bind(&Gui::HandleEvent, this, std::placeholders::_1)); + inputCon = input.AddHandler([this](const SDL_Event& event) { return this->HandleEvent(event); }); } #ifdef HEADLESS @@ -81,7 +80,6 @@ void Gui::Clean() { Gui::~Gui() { Clean(); - inputCon.disconnect(); } void Gui::AddElement(GuiElement* elem, bool asBackground) diff --git a/rts/aGui/Gui.h b/rts/aGui/Gui.h index a5a8c7fd5f..458f81799f 100644 --- a/rts/aGui/Gui.h +++ b/rts/aGui/Gui.h @@ -4,7 +4,6 @@ #define GUI_H #include -#include #include "System/Input/InputHandler.h" union SDL_Event; @@ -30,9 +29,9 @@ class Gui bool MouseOverElement(const GuiElement*, int x, int y) const; -private: bool HandleEvent(const SDL_Event& ev); - InputHandler::SignalType::connection_type inputCon; +private: + InputHandler::HandlerTokenT inputCon; struct GuiItem { diff --git a/rts/aGui/GuiElement.h b/rts/aGui/GuiElement.h index f6eb170b18..ec5e6d8031 100644 --- a/rts/aGui/GuiElement.h +++ b/rts/aGui/GuiElement.h @@ -4,6 +4,8 @@ #define GUIELEMENT_H #include +#include +#include #include #include "System/Color.h" @@ -13,6 +15,9 @@ namespace agui class GuiElement { +public: + using OnClickVoidType = std::function; + using OnClickStringType = std::function; public: GuiElement(GuiElement* parent = nullptr); virtual ~GuiElement(); diff --git a/rts/aGui/LineEdit.cpp b/rts/aGui/LineEdit.cpp index d80fd9ba90..cc9cb60c6e 100644 --- a/rts/aGui/LineEdit.cpp +++ b/rts/aGui/LineEdit.cpp @@ -139,7 +139,7 @@ bool LineEdit::HandleEventSelf(const SDL_Event& ev) break; } case SDLK_RETURN: { - DefaultAction.emit(); + DefaultAction(); return true; } } diff --git a/rts/aGui/LineEdit.h b/rts/aGui/LineEdit.h index ff7b5ebcf1..9ab59a084a 100644 --- a/rts/aGui/LineEdit.h +++ b/rts/aGui/LineEdit.h @@ -4,7 +4,6 @@ #define LINE_EDIT_H #include -#include #include "GuiElement.h" @@ -25,7 +24,7 @@ class LineEdit : public GuiElement void SetFocus(bool focus); void SetCrypt(bool focus); - slimsig::signal DefaultAction; + OnClickVoidType DefaultAction; private: virtual void DrawSelf(); diff --git a/rts/aGui/List.cpp b/rts/aGui/List.cpp index edc5da1ae1..f3a9569903 100644 --- a/rts/aGui/List.cpp +++ b/rts/aGui/List.cpp @@ -159,7 +159,7 @@ bool List::MouseUpdate(int x, int y) { if (nCurIndex == place && (clickedTime + spring_msecs(250)) > spring_now()) { - FinishSelection.emit(); + FinishSelection(); } clickedTime = spring_now(); place = nCurIndex; @@ -430,7 +430,7 @@ bool List::KeyPressed(int k, bool isRepeat) query = query.substr(0, query.length() - 1); return Filter(true); } else if (k == SDLK_RETURN) { - FinishSelection.emit(); + FinishSelection(); return true; } else if ((k & ~0xFF) != 0) { // This prevents isalnum from asserting on msvc debug crt diff --git a/rts/aGui/List.h b/rts/aGui/List.h index 496096fb8b..5661c6b50e 100644 --- a/rts/aGui/List.h +++ b/rts/aGui/List.h @@ -5,7 +5,6 @@ #include #include -#include #include "GuiElement.h" #include "System/Misc/SpringTime.h" @@ -43,7 +42,7 @@ class List : public GuiElement int cancelPlace; std::string tooltip; - slimsig::signal FinishSelection; // Return or Double-Click + OnClickVoidType FinishSelection; // Return or Double-Click void SetFocus(bool focus); void RefreshQuery(); diff --git a/rts/aGui/Window.cpp b/rts/aGui/Window.cpp index e42b896b2b..0a809c88cf 100644 --- a/rts/aGui/Window.cpp +++ b/rts/aGui/Window.cpp @@ -105,7 +105,7 @@ bool Window::HandleEventSelf(const SDL_Event& ev) case SDL_KEYDOWN: { if (ev.key.keysym.sym == SDLK_ESCAPE) { - WantClose.emit(); + WantClose(); return true; } break; diff --git a/rts/aGui/Window.h b/rts/aGui/Window.h index 35590caaad..d577e72fc0 100644 --- a/rts/aGui/Window.h +++ b/rts/aGui/Window.h @@ -4,7 +4,6 @@ #define WINDOW_H #include -#include #include "GuiElement.h" @@ -16,7 +15,7 @@ class Window : public GuiElement Window(const std::string& title = "", GuiElement* parent = NULL); virtual void AddChild(GuiElement* elem); - slimsig::signal WantClose; + OnClickVoidType WantClose; protected: std::string title; diff --git a/rts/lib/slimsig/LICENSE b/rts/lib/slimsig/LICENSE deleted file mode 100644 index 04243d91c6..0000000000 --- a/rts/lib/slimsig/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Chris Tarquini - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/rts/lib/slimsig/README.md b/rts/lib/slimsig/README.md deleted file mode 100644 index 72460515c5..0000000000 --- a/rts/lib/slimsig/README.md +++ /dev/null @@ -1,60 +0,0 @@ -slimsig -======= -![slimsig](http://i.imgur.com/rpC5pot.png?1) - -A light-weight alternative to Boost::Signals2 and SigSlot++. - -## What makes this different from all the other Signal/Slot libraries out there? - - Light-weight: Only one header file, <200 lines of code. No dependencies (unless you're running the unit tests) - - Uses vectors as the underlying storage. - - This is a very important and disguinshing factor between slimsig and other libraries. - The idea is that your signal will spend much more time iterating and executing slots than adding/removing them. - Most implementations use a double or singly linked list which kill performance on modern CPUs by completely trashing the cache and eliminating the CPU's ability to optimize and use SIMD instructions. This is a big deal! - - - Less memory allocations: Because we use a vector instead of a list, we can re-use memory we've already allocated from deleted slots for future slots without hitting the heap again. STL's linked list allocates and deallocates every time you add/remove an item. Bad for cache locality, bad for fragmentation, bad for your soul! - - Supports adding/removing slots while the signal is running (despite it being a vector) - - Removing slots should still be very fast. It uses std::remove_if to iterate/execute slots - Meaning that if there are disconnected slots they are removed quickly after iteration - - Custom allocators for more performance tweaking - -## How to use it -`slimgsig` is a header only library. Just add `include/slimsig/slimgsig.h` to your project and you're good to go. I'd reccomend adding the path to `include` to your header search directories so you can include it as `` similiar to how you would use boost and other libraries. - -## How to use with gyp -If you're using gyp you can simply add `"includes": ["path/to/slimsig.gypi"]` to your target and the appropriate header search paths will be added for you - -## How to run the unit tests -![unit tests](http://i.imgur.com/5AriT6o.png) -If you using gyp just execute `$ gyp --depth=./ slimsig.gyp` from the command line to generate an project file for your platform. It defaults to xcode on OSX, Visual Studio on Windows and a makefile on linux/posix systems but you can choose which one you want with `-f [projecttype]`. See the gyp documentation for more details. - -Once you've got your project just open it up and build the `test-runner` target and run it. We use bandit as a unit-test framework so you can execute a bunch of neat commands like `./test-runner --reporter=spec --only connection` to only run connection related tests and show the output as in a neat doc-like format. For more information see the [bandit documentation](http://banditcpp.org/). - -## How do I get started with slimsignal? -The usage is pretty much the same as Boost::Signals2. There's a `signal` class, `connection`, and `scoped_connection` that work in very much the same way minus a lot of the extra (but heavy) features boost includes such as object tracking or signals that return values. - -I'll write up some proper documentation soon but for now check out `test/test.cpp` for some examples. - -## While still being light-weight it still supports: - - connections/scoped_connections - - connection.disconnect()/connection.connected() can be called after the signal stops existing - There's a small overhead because of the use of a shared_ptr for each slot, however, my average use-case - Involves adding 1-2 slots per signal so the overhead is neglible, especially if you use a custom allocator such as boost:pool - - To keep it simple I left out support for slots that return values, though it shouldn't be too hard to implement. - I've also left thread safety as something to be handled by higher level libraries - Much in the spirit of other STL containers. My reasoning is that even with thread safety sort of baked in - the user would still be responsible making sure slots don't do anything funny if they are executed on different threads. - All the mechanics for this would complicate the library, confuse users into thinking that your syncronization problems are magically sorted, and slow it down considerably even if you aren't using threads. - Syncronization decisions are very application specific and simply don't belong in a basic building blocks library like this. - -## Inspiration -- Boost::Signals2 - Beautiful, powerful, but heavy-weight Signal/Slot library that does everything but your taxes -- SigSlot++ -- ssig - Another light-weight implementation, original inspiration for sigslim - -## Benchmarks -- Coming soon! Maybe! - - - diff --git a/rts/lib/slimsig/include/slimsig/connection.h b/rts/lib/slimsig/include/slimsig/connection.h deleted file mode 100644 index 9e46a3c82f..0000000000 --- a/rts/lib/slimsig/include/slimsig/connection.h +++ /dev/null @@ -1,125 +0,0 @@ -// -// connection.h -// slimsig -// -// Created by Christopher Tarquini on 4/21/14. -// -// - -#ifndef slimsig_connection_h -#define slimsig_connection_h -#include -#include -#include -#include -#include - -namespace slimsig { -template -class connection; - -template -class signal_base; - // detail - - template - class connection { - using slot = typename Signal::slot; - using slot_type = slot; - using slot_list_iterator = typename Signal::slot_list::iterator; - using slot_storage = typename Signal::slot_list; - using slot_id = typename slot::slot_id; - using signal_holder = typename Signal::signal_holder; - connection(std::weak_ptr slots, const slot_type& slot) : connection(std::move(slots), slot.m_slot_id) {}; - connection(std::weak_ptr slots, unsigned long long slot_id) : m_slots(std::move(slots)), m_slot_id(slot_id) {}; - public: - connection() {}; // empty connection - connection(const connection& other) : m_slots(other.m_slots), m_slot_id(other.m_slot_id) {}; - connection(connection&& other) : m_slots(std::move(other.m_slots)), m_slot_id(other.m_slot_id) {}; - - connection& operator=(connection&& rhs) { - this->swap(rhs); - return *this; - } - connection& operator=(const connection& rhs) { - m_slot_id = rhs.m_slot_id; - m_slots = rhs.m_slots; - return *this; - } - - void swap(connection& other) { - using std::swap; - swap(m_slots, other.m_slots); - swap(m_slot_id, other.m_slot_id); - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline explicit operator bool() const { return connected(); }; - bool connected() const { - const auto slots = m_slots.lock(); - if (slots && slots->signal != nullptr) { - return slots->signal->connected(m_slot_id); - //auto slot = (*slots)->find(m_slot_id); - //return slot != (*slots)->cend() ? slot->connected() : false; - } - return false; - } - - void disconnect() { - std::shared_ptr slots = m_slots.lock(); - if (slots != nullptr && slots->signal != nullptr) { - slots->signal->disconnect(m_slot_id); - //auto slot = *slots->find(m_slot_id); - //if (slot != slots->end()) slot->disconnect(); - } - } - template - friend class signal_base; - template < class T, class IDGenerator, class FlagType, class Allocator> - friend class slot_list; - - - private: - std::weak_ptr m_slots; - slot_id m_slot_id; - }; - - template - class scoped_connection { - public: - scoped_connection() : m_connection() {}; - scoped_connection(const connection& target) : m_connection(target) {}; - scoped_connection(const scoped_connection&) = delete; - scoped_connection(scoped_connection&& other) : m_connection(other.m_connection) {}; - - scoped_connection& operator=(const connection& rhs) { - m_connection = rhs; - }; - scoped_connection& operator=(scoped_connection&& rhs) { - this->swap(rhs); - return *this; - }; - void swap(scoped_connection& other) { - m_connection.swap(other.m_connection); - }; - connection release() { - connection ret{}; - m_connection.swap(ret); - return ret; - } - ~scoped_connection() { - m_connection.disconnect(); - } - private: - connection m_connection; - }; - - template - scoped_connection make_scoped_connection(connection&& target) { - return scoped_connection(std::forward(target)); - }; - -} - -#endif diff --git a/rts/lib/slimsig/include/slimsig/detail/concat_iterator.h b/rts/lib/slimsig/include/slimsig/detail/concat_iterator.h deleted file mode 100644 index 9b41b9e02d..0000000000 --- a/rts/lib/slimsig/include/slimsig/detail/concat_iterator.h +++ /dev/null @@ -1,157 +0,0 @@ -// -// concat_iterator.h -// slimsig -// -// Created by Christopher Tarquini on 4/22/14. -// -// based on this stackoverflow post: -// http://stackoverflow.com/questions/757153/concatenating-c-iterator-ranges-into-a-const-vector-member-variable-at-constru/757328#757328 - -#ifndef slimsig_concat_iterator_h -#define slimsig_concat_iterator_h -#include -#include -#include -// compacted syntax for brevity... -template > -struct concat_iterator : std::iterator< - typename Traits::iterator_category, - typename Traits::value_type, - typename Traits::difference_type, - typename Traits::pointer_type, - typename Traits::reference_type - > -{ - using iterator_traits = std::iterator_traits; - using iterator = Iterator; -public: - using size_type = std::size_t; - using range = std::pair; - using reference = typename iterator_traits::reference_type; - using pointer = typename iterator_traits::pointer_type; - - concat_iterator(range first, range second) - : m_range1(std::move(first)), m_range2(std::move(second)), m_current(first.first), m_is_first(true) {}; - concat_iterator(const concat_iterator& other) = default; - concat_iterator(concat_iterator&&) = default; - concat_iterator& operator=(const concat_iterator&) = default; - concat_iterator& operator=(concat_iterator&&) = default; - inline bool operator ==(const concat_iterator& other) const { - return m_current == m_current; - } - inline bool operator !=(const concat_iterator& other) const{ - return !(*this == other); - } - inline bool operator >(const concat_iterator& other) const{ - return m_current > other.m_current; - } - inline bool operator >(const concat_iterator& other) const{ - return !(*this < other); - } - inline bool operator <=(const concat_iterator& other) const{ - return (*this == other) || (*this < other); - } - inline bool operator >=(const concat_iterator& other) const{ - return (*this == other) || (*this > other); - } - - concat_iterator& operator++() { - m_current++; - if (m_is_first && m_current == range1.second) { - m_current = range2.first; - m_is_first = false; - } - return this; - } - concat_iterator operator++(int) { - concat_iterator it(*this); - ++(*this); - return it; - } - concat_iterator& operator--() { - using std::prev; - if (!m_is_first && m_current == range2.first) { - m_current = prev(range1.second); - m_is_first = true; - } else { - m_current--; - } - return *this; - } - concat_iterator operator--(int) { - concat_iterator it(*this); - --(*this); - return it; - } - concat_iterator& operator+=(difference_type offset) - { - if (offset > 0) { - auto delta = m_is_first ? offset - std::distance(m_current, range1.second) : -1; - if (delta >= 0) { - m_is_first = false; - m_current = m_range2.first + delta; - } else { - m_current += offset; - } - return *this; - } else { - return *this -= -offset; - } - } - concat_iterator& operator-=(difference_type offset) - { - if (offset > 0) { - auto delta = !m_is_first ? offset - (std::distance(m_current, range2.first)) : -1; - if (delta >= 1) { - m_is_first = true; - m_current = range1.second - delta; - } else { - m_current -= offset; - } - return *this; - } else { - return *this += -offset; - } - } - inline reference operator*() const{ - return *m_current; - } - inline pointer operator->() const{ - return m_current.operator->(); - } - concat_iterator operator+(difference_type offset) const{ - concat_iterator it(*this); - it += offset; - return it; - } - concat_iterator operator-(difference_type offset) const { - concat_iterator it(*this); - it -= offset; - return it; - } - reference operator[](size_type offset) const{ - concat_iterator it(*this); - it += offset; - return *it; - } - - -private: - range m_range1; - range m_range2; - iterator m_current; - bool m_is_first; -}; - -template -concat_iterator concat_begin( T1 b1, T1 e1, T2 b2, T2 e2 ) -{ - return concat_iterator(b1,e1,b2,e2); -} -template -concat_iterator concat_end( T1 b1, T1 e1, T2 b2, T2 e2 ) -{ - return concat_iterator(e1,e1,e2,e2); -} - -#endif diff --git a/rts/lib/slimsig/include/slimsig/detail/signal_base.h b/rts/lib/slimsig/include/slimsig/detail/signal_base.h deleted file mode 100644 index b564dd2c28..0000000000 --- a/rts/lib/slimsig/include/slimsig/detail/signal_base.h +++ /dev/null @@ -1,372 +0,0 @@ -// -// signal_base.h -// slimsig -// -// Created by Christopher Tarquini on 4/21/14. -// -// - -#ifndef slimsig_signal_base_h -#define slimsig_signal_base_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -namespace slimsig { - -template -struct signal_traits; - -template -struct signal_traits { - using return_type = R; - using slot_id_type = std::size_t; - using depth_type = unsigned; -}; - -template -class signal; - -template -class signal_base; - -template -void swap(signal& lhs, signal& rhs); - -namespace detail { - template - inline void each(const Container& container, typename Container::size_type begin, typename Container::size_type end, const Callback& fn) - { - for(; begin != end; begin++) { - fn(container[begin]); - } - } - template - inline void each_n(const Container& container, typename Container::size_type begin, typename Container::size_type count, const Callback& fn) - { - return each(container, begin, begin + count, fn); - } -} -template -class signal_base -{ - struct emit_scope; -public: - using signal_traits = SignalTraits; - using return_type = typename signal_traits::return_type; - using callback = std::function; - using allocator_type = Allocator; - using slot = basic_slot; - using list_allocator_type = typename std::allocator_traits::template rebind_traits::allocator_type; - using slot_list = std::vector; - - using connection_type = connection; - using extended_callback = std::function; - using slot_id = typename signal_traits::slot_id_type; - using slot_reference = typename slot_list::reference; - using const_slot_reference = typename slot_list::const_reference; - using size_type = std::size_t; -public: - static constexpr auto arity = sizeof...(Args); - struct signal_holder { - signal_holder(signal_base* p) : signal(p) {}; - signal_base* signal; - }; - template - struct argument - { - static_assert(N < arity, "error: invalid parameter index."); - using type = typename std::tuple_element>::type; - }; - - // allocator constructor - signal_base(const allocator_type& alloc) : - pending(alloc), - m_self(nullptr), - last_id(), - m_size(0), - m_offset(0), - allocator(alloc), - m_depth(0){}; - - signal_base(size_t capacity, const allocator_type& alloc = allocator_type{}) - : signal_base(alloc) { - pending.reserve(capacity); - }; - - signal_base(signal_base&& other) { - this->swap(other); - } - signal_base& operator=(signal_base&& other) { - this->swap(other); - return *this; - } - // no copy - signal_base(const signal_base&) = delete; - signal_base& operator=(const signal_base&) = delete; - void swap(signal_base& rhs) { - using std::swap; - using std::back_inserter; - using std::copy_if; - //using std::not1; - if (this != &rhs) { - #if !defined(NDEBUG) || (defined(SLIMSIG_SWAP_GUARD) && SLIMSIG_SWAP_GUARD) - if (is_running() || rhs.is_running()) - throw new std::logic_error("Signals can not be swapped or moved while emitting"); - #endif - swap(pending, rhs.pending); - swap(m_self, rhs.m_self); - if (m_self) m_self->signal = this; - if (rhs.m_self) rhs.m_self->signal = &rhs; - swap(last_id, rhs.last_id); - swap(m_size, rhs.m_size); - swap(m_offset, rhs.m_offset); - if (std::allocator_traits::propagate_on_container_swap::value) - swap(allocator, rhs.allocator); - swap(m_depth, rhs.m_depth); - } - } - - return_type emit(Args... args) { - using detail::each; - // scope guard - emit_scope scope { *this }; - - auto end = pending.size(); - assert(m_offset <= end); - if (end - m_offset == 0) return; - assert(end > 0); - --end; - for(; m_offset != end; m_offset++) { - const_slot_reference slot = pending[m_offset]; - if (slot) slot(args...); - } - auto& slot = pending[end]; - if (slot) slot(std::forward(args)...); - } - return_type operator()(Args... args) { - return emit(std::forward(args)...); - } - - inline connection_type connect(callback slot) - { - auto sid = prepare_connection(); - emplace(sid, std::move(slot)); - return { m_self, sid }; - }; - - inline connection_type connect_extended(extended_callback slot) - { - struct extended_slot { - callback fn; - connection_type connection; - R operator()(Args&&... args) { - return fn(connection, std::forward(args)...); - } - }; - return create_connection(std::move(slot)); - } - - template - inline connection_type connect(std::shared_ptr> signal) { - using signal_type = slimsig::signal; - struct signal_slot { - std::weak_ptr handle; - connection_type connection; - R operator()(Args&&... args) { - auto signal = handle.lock(); - if (signal) { - return signal->emit(std::forward(args)...); - } else { - connection.disconnect(); - return; - } - } - }; - return create_connection(std::move(signal)); - } - - connection_type connect_once(callback slot) { - struct fire_once { - callback fn; - connection_type conn; - R operator() (Args&&... args) { - auto scoped_connection = make_scoped_connection(std::move(conn)); - return fn(std::forward(args)...); - } - }; - return create_connection(std::move(slot)); - } - - - void disconnect_all() { - using std::for_each; - if (is_running()) { - m_offset = pending.size(); - m_size = 0; - } else { - pending.clear(); - m_size = 0; - } - // if we've used up a lot of id's we can take advantage of the fact that - // all connections are based on the current signal_holder pointer - // and reset our last_id to 0 without causing trouble with old connections - if (m_self && last_id > std::numeric_limits::max() / 3) { - m_self->signal = nullptr; - m_self.reset(); - last_id = slot_id(); - } - } - - const allocator_type& get_allocator() const { - return allocator; - } - inline bool empty() const { - return m_size == 0; - } - inline size_type slot_count() const { - return m_size; - } - inline size_type max_size() const { - return std::min(std::numeric_limits::max(), pending.max_size()); - } - inline size_type remaining_slots() const { - return max_size() - last_id; - } - - size_type max_depth() const { - return std::numeric_limits::max(); - } - size_type get_depth() const { - return m_depth; - } - bool is_running() const { - return m_depth > 0; - } - - ~signal_base() { - if (m_self) m_self->signal = nullptr; - } - template - friend class signal; - template - friend class slimsig::connection; -private: - struct emit_scope{ - signal_base& signal; - emit_scope(signal_base& context) : signal(context) { - signal.m_depth++; - } - emit_scope() = delete; - emit_scope(const emit_scope&) = delete; - emit_scope(emit_scope&&) = delete; - ~emit_scope() { - using std::move; - using std::for_each; - using std::remove_if; - auto depth = --signal.m_depth; - // if we completed iteration (depth = 0) collapse all the levels into the head list - if (depth == 0) { - auto m_size = signal.m_size; - auto& pending = signal.pending; - // if the size is different than the expected size - // we have some slots we need to remove - if (m_size != pending.size()) { - // remove slots from disconnect_all - pending.erase(pending.begin(), pending.begin() + signal.m_offset); - pending.erase(remove_if(pending.begin(), pending.end(), &is_disconnected), pending.end()); - } - signal.m_offset = 0; - assert(m_size == pending.size()); - } - } - }; - - static bool is_disconnected(const_slot_reference slot) { return !bool(slot); }; - - inline bool connected(slot_id index) - { - using std::lower_bound; - auto end = pending.cend(); - auto slot = lower_bound(pending.cbegin() + m_offset, end, index, [] (const_slot_reference slot, const slot_id& index) { - return slot < index; - }); - if (slot != end && slot->m_slot_id == index) return slot->connected(); - return false; - }; - - inline void disconnect(slot_id index) - { - using std::lower_bound; - auto end = pending.end(); - auto slot = lower_bound(pending.begin() + m_offset, end, index, [] (slot_reference slot, const slot_id& index) { - return slot < index; - }); - if (slot != end && slot->m_slot_id == index) { - if (slot->connected()) { - slot->disconnect(); - m_size -= 1; - } - - } - }; - - template -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline connection_type create_connection(T&& slot) - { - auto sid = prepare_connection(); - emplace(sid, C { std::move(slot), {m_self, sid} }); - return connection_type { m_self, sid }; - }; -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline slot_id prepare_connection() - { - // lazy initialize to put off heap allocations if the user - // has not connected a slot - if (!m_self) m_self = std::make_shared(this); - assert((last_id < std::numeric_limits::max() - 1) && "All available slot ids for this signal have been exhausted. This may be a sign you are misusing signals"); - return last_id++; - }; - - template -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline void emplace(SlotArgs&&... args) - { - pending.emplace_back(std::forward(args)...); - m_size++; - }; -protected: - std::vector pending; -private: - std::shared_ptr m_self; - slot_id last_id; - std::size_t m_size; - std::size_t m_offset; - allocator_type allocator; - unsigned m_depth; - -}; - - template - void swap(signal& lhs, signal& rhs) { - using std::swap; - lhs.swap(rhs); - } -} - -#endif diff --git a/rts/lib/slimsig/include/slimsig/detail/slot.h b/rts/lib/slimsig/include/slimsig/detail/slot.h deleted file mode 100644 index 7414355e6a..0000000000 --- a/rts/lib/slimsig/include/slimsig/detail/slot.h +++ /dev/null @@ -1,327 +0,0 @@ -// -// signal_set.h -// slimsig -// -// Created by Christopher Tarquini on 4/23/14. -// -// - -#ifndef slimsig_signal_set_h -#define slimsig_signal_set_h - -#include -#include -#include -#include - -namespace slimsig { -namespace detail { - -template -#ifdef __GNUC__ -__attribute__((always_inline)) -#endif -inline T default_value() { return T(); } -template<> -#ifdef __GNUC__ -__attribute__((always_inline)) -#endif -inline void default_value() {}; -}; - -template -class basic_slot; - -template -class basic_slot { -public: - using callback = std::function; - using slot_id = SlotID; - - basic_slot(slot_id sid, callback fn) : m_fn(std::move(fn)), m_slot_id(sid), m_is_connected(bool(m_fn)), m_is_running(false) {}; - basic_slot() : basic_slot(0, nullptr) {}; - template - basic_slot(slot_id sid, Arguments&&... args) : m_fn(std::forward(args)...), m_slot_id(sid), m_is_connected(bool(m_fn)), m_is_running(false) {}; - basic_slot(basic_slot&&) = default; - basic_slot(const basic_slot&) = default; - inline basic_slot& operator=(const basic_slot&) = default; - inline basic_slot& operator=(basic_slot&&) = default; -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator==(const basic_slot& other) const{ - return m_slot_id == other.m_slot_id; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator==(const slot_id& other) const { - return m_slot_id == other; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator <(const basic_slot& other) const { - return m_slot_id < other.m_slot_id; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator <(const slot_id& other) const { - return m_slot_id < other; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator >(const basic_slot& other) const { - return m_slot_id > other.m_slot_id; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator >(const slot_id& other) const { - return m_slot_id > other; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator <=(const slot_id& other) const { - return m_slot_id <= other; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool operator >=(const slot_id& other) const { - return m_slot_id >= other; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline explicit operator bool() const{ - return m_is_connected; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline bool connected() const { - return m_is_connected; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline void disconnect() { - m_is_connected = false; - if (!m_is_running) { - m_fn = nullptr; - } - } -#ifdef __GNUC__ - __attribute__((always_inline, deprecated("Use operator()"))) -#endif - inline const callback& operator*() const{ - return m_fn; - }; -#ifdef __GNUC__ - __attribute__((always_inline, deprecated("Use operator()"))) -#endif - inline const callback* operator->() const { - return &m_fn; - } -#ifdef __GNUC__ - __attribute__((always_inline)) -#endif - inline R operator() (Args... args) const{ - struct invoke_guard - { - const basic_slot& slot; - ~invoke_guard() { slot.m_is_running = false;} - } guard { *this }; - m_is_running = true; - return m_fn(std::forward(args)...); - } - callback m_fn; - slot_id m_slot_id; - bool m_is_connected; - mutable bool m_is_running; -}; - -/** - * Specialized container adaptor for slot/callback values - * Because of some assumptions we can make about how signals will use - * this list, we can achieve great performance boosts over using a standard containers alone - * Requirements: - * T must meet all requirements of Container - * SlotID must be post-incrementable, equality comparable and less than comparable - * SlotID must always be unique for new values added to the list - * SlotID must always increase in value for new values (new slots must compare greater than old slots) - * SlotID must support default initilization - * The return of SlotID++ will be stored with each slot for access - * - * We use this type of lookup for slots because we need a way to access slots after the vectors - * iterators have been invalidated, but we need to do this quickly. - * - * To accomplish this we use a simple linear search if the container contains less than 4 elements - * Otherwise we use std::lower_bound to quickly locate the slot with this ID in the vector - * This requires the vector to be sorted with lower IDs (older slots) first - * - * Because generally slots aren't removed or queried nearly as much as they are emitted - * Applications will see huge performance gains over using a list or a vector of shared_ptr's - * due to the memory being contigious. Additions are pretty snappy in most cases because we don't - * need to make allocations for every slot, only when we've exceeded our underlying vectors capacity - * - * In multithreaded applications it's reccomended that SlotIDGenerator be an atomic type or use mutexes to syncronize. - * - * This would be better with some sort of Optional type - * - */ -template < class T, - class IDGenerator = std::size_t, - class FlagType = bool, - class Allocator = std::allocator> - > -class slot_list : public std::enable_shared_from_this>{ - using id_generator = IDGenerator; - using flag = FlagType; - static auto slot_id_helper(IDGenerator gen) -> decltype(gen++); -public: - using slot_id = decltype(slot_id_helper(std::declval())); - using slot = basic_slot; - using callback = typename slot::callback; - using allocator_type = typename std::allocator_traits::template rebind_traits::allocator_type; - using container_type = std::vector; - using value_type = typename container_type::value_type; - using reference = typename container_type::reference; - using const_reference = typename container_type::const_reference; - using size_type = typename container_type::size_type; - using pointer = typename container_type::pointer; - using iterator = typename container_type::iterator; - using const_iterator = typename container_type::const_iterator; - - slot_list() : active(), pending(), last_id(1), is_locked(false) {}; - slot_list(allocator_type alloc) : active{alloc}, pending{std::move(alloc)}, last_id(1), is_locked(false) {}; - slot_list(slot_list&&) = default; - slot_list(const slot_list&) = default; - - bool try_lock() { lock(); return true; } - void lock() { is_locked = true; } - - - void unlock() { - using std::make_move_iterator; - using std::sort; - - struct guard_t{ - flag& locked; - container_type& pending; - ~guard_t() { locked = false; pending.clear();}; - } guard { is_locked, pending }; - // sort offset in case of error - auto offset = active_size() - !active_empty(); - try { - active.insert(active.end(), make_move_iterator(pending.begin()), make_move_iterator(pending.end())); - } catch (...) { - // make sure we are still sorted properly - sort(active.begin() + offset, active.end()); - throw; - } - } - - bool locked() const noexcept (noexcept(bool(std::declval()))) { return is_locked; } - - slot_id push(const value_type& value) { - using std::move; - auto& queue = !is_locked ? active : pending; - auto sid = last_id++; - queue.emplace_back({ sid, move(value)}); - return sid; - } - - slot_id push(value_type&& value) { - using std::move; - auto& queue = !is_locked ? active : pending; - auto sid = last_id++; - queue.emplace_back({ sid, move(value)}); - return sid; - } - - template - slot_id emplace(Args&&... args) { - auto& queue = !is_locked ? active : pending; - auto sid = last_id++; - queue.emplace_back(sid, std::forward(args)...); - return sid; - } - - template - slot_id emplace_extended(Args&&... args) { - auto& queue = !is_locked ? active : pending; - auto sid = last_id++; - queue.emplace_back(sid, U{std::forward(args)..., {this->shared_from_this(), sid}}); - return sid; - } - - - - inline iterator erase(const_iterator position) { return active.erase(position); } - inline iterator erase(const_iterator begin, const_iterator end) { return active.erase(begin, end); } - - inline iterator begin() { return active.begin(); } - inline iterator end() { return active.end(); } - inline const_iterator cbegin() const { return active.cbegin(); } - inline const_iterator cend() const { return active.cend(); } - inline size_type active_size() const { return active.size(); } - inline reference back() { return active.back(); } - inline const_reference cback() const { return active.cback(); } - inline size_type pending_size() const { return pending_size(); } - inline size_type total_size() const { return active.size() + pending.size(); } - inline void clear() { active.clear(); pending.clear(); } - inline bool active_empty() const { return active_size() == 0; } - inline bool pending_empty() const { return pending_size() == 0; } - inline bool empty() const { return total_size() == 0; } - - iterator find(slot_id index) noexcept { - auto end = active.end(); - auto slot = find(index, active.begin(), end); - if (slot == end) { - auto pend = pending.end(); - slot = find(index, pending.begin(), pend); - if (slot == pend) slot = end; - } - return slot; - }; - - const_iterator find(slot_id index) const noexcept{ - auto end = active.cend(); - auto slot = find(index, active.cbegin(), end); - if (slot == end) { - auto pend = pending.cend(); - slot = find(index, pending.cbegin(), pend); - if (slot == pend) slot = end; - } - return slot; - }; -private: - // for internal use only - template - static Iterator find(slot_id index, Iterator begin, Iterator end) noexcept{ - using std::distance; - using std::lower_bound; - using std::find_if; - using std::bind; - using std::less_equal; - - begin = find_if(lower_bound(begin, end, index), end, [&] (const_reference slot){ - return index >= index; - }); - return begin != end && *begin == index ? begin : end; - }; - container_type active; - container_type pending; - id_generator last_id; - flag is_locked; -}; - -} - - -#endif diff --git a/rts/lib/slimsig/include/slimsig/detail/slot_call_iterator.h b/rts/lib/slimsig/include/slimsig/detail/slot_call_iterator.h deleted file mode 100644 index 63a921407f..0000000000 --- a/rts/lib/slimsig/include/slimsig/detail/slot_call_iterator.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// slot_call_iterator.h -// slimsig -// -// Created by Christopher Tarquini on 4/22/14. -// -// - -#ifndef slimsig_slot_call_iterator_h -#define slimsig_slot_call_iterator_h -#include -namespace slimsig { namespace detail { -template -class slot_call_iterator : std::iterator { - -} -}} - - -#endif diff --git a/rts/lib/slimsig/include/slimsig/detail/slot_iterator.h b/rts/lib/slimsig/include/slimsig/detail/slot_iterator.h deleted file mode 100644 index 1608ebb56b..0000000000 --- a/rts/lib/slimsig/include/slimsig/detail/slot_iterator.h +++ /dev/null @@ -1,119 +0,0 @@ -// -// slot_iterator.h -// slimsig -// -// Created by Christopher Tarquini on 5/20/14. -// -// - -#ifndef slimsig_slot_iterator_h -#define slimsig_slot_iterator_h -#include -#include -#include -namespace slimsig { - - -template > -class offset_iterator : public std::iterator< - typename Traits::iterator_category, - typename Traits::value_type, - typename Traits::difference_type, - typename Traits::pointer, - std::forward_iterator_tag> -{ -using traits = std::iterator_traits; -public: - using container_type = typename std::decay::type; - using size_type = typename Container::size_type; - using reference = typename traits::reference; - using pointer = typename traits::pointer; - using difference_type = typename traits::difference_type; - using value_type = typename traits::value_type; - - offset_iterator() : p_container(nullptr), m_offset(0) {}; - offset_iterator(const offset_iterator&) = default; - offset_iterator(offset_iterator&&) = default; - offset_iterator& operator=(const offset_iterator&) = default; - offset_iterator& operator=(offset_iterator&&) = default; - bool operator ==(const offset_iterator& rhs) const { - return m_offset == rhs.m_offset && p_container == rhs.p_container; - } - bool operator !=(const offset_iterator rhs) const{ - return !(*this == rhs); - } - bool operator >(const offset_iterator rhs) const{ - return m_offset > rhs.m_offset && p_container > p_container; - } - bool operator <(const offset_iterator rhs) const{ - return m_offset < rhs.m_offset && p_container < p_container; - } - bool operator <=(const offset_iterator rhs) const { - return m_offset <= rhs.m_offset && p_container <= p_container; - } - bool operator >=(const offset_iterator rhs) const { - return m_offset >= rhs.m_offset && p_container >= p_container; - } - offset_iterator(container_type& container, size_type offset = 0) : p_container(&container), m_offset(offset) {}; - reference operator*() { - return std::begin(*p_container) + m_offset; - } - pointer operator->() { - return &(std::begin(*p_container) + m_offset); - } - offset_iterator& operator++() { - ++m_offset; - return *this; - } - offset_iterator operator++(int) { - offset_iterator it(*this); - ++m_offset; - return it; - } - size_type size() const { - return p_container == nullptr ? 0 : p_container->size(); - }; - operator bool() const { - return p_container != nullptr && m_offset < p_container->size(); - } - const container_type* p_container; - size_type m_offset; -}; -template > -class slot_iterator : private offset_iterator -{ -using base = offset_iterator; -public: - using base::container_type; - using base::size_type; - using base::reference; - using base::pointer; - using base::difference_type; - using base::value_type; - - using base::base; - using base::operator ==; - using base::operator !=; - using base::operator >; - using base::operator <; - using base::operator >=; - using base::operator <=; - operator bool() const { - return bool(*this) && bool(**this); - } - slot_iterator& operator++() { - do { - base::operator++(); - } while (bool(*this) && !(bool(**this))); - return *this; - } - slot_iterator& operator++(int) { - slot_iterator it(*this); - ++(*this); - return it; - } -}; - -} - -#endif diff --git a/rts/lib/slimsig/include/slimsig/slimsig.h b/rts/lib/slimsig/include/slimsig/slimsig.h deleted file mode 100644 index 9e689823b3..0000000000 --- a/rts/lib/slimsig/include/slimsig/slimsig.h +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Slimmer Signals - * Copyright (c) 2014 Christopher Tarquini - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * Slimmer Signals - * Inspired by Boost::Signals2 and ssig - * - * Main Differences between this library and all the other signal libraries: - * - Light-weight: No unessarry virtual calls besides the ones inherit with std::function - * - Uses vectors as the underlying storage - * The theory is that you'll be emitting signals far more than you'll be adding slots - * so using vectors will improve performance greatly by playing nice with the CPUs cache and taking - * advantage of SIMD - * - Supports adding/removing slots while the signal is running (despite it being a vector) - * - Removing slots should still be fast as it uses std::remove_if to iterate/execute slots - * Meaning that if there are disconnected slots they are removed quickly after iteration - * - Custom allocators for more performance tweaking - * - * While still being light-weight it still supports: - * - connections/scoped_connections - * - connection.disconnect()/connection.connected() can be called after the signal stops existing - * There's a small overhead because of the use of a shared_ptr for each slot, however, my average use-case - * Involves adding 1-2 slots per signal so the overhead is neglible, especially if you use a custom allocator such as boost:pool - * - * To keep it simple I left out support for slots that return values, though it shouldn't be too hard to implement. - * I've also left thread safety as something to be handled by higher level libraries - * Much in the spirit of other STL containers. My reasoning is that even with thread safety sort of baked in - * The user would still be responsible making sure slots don't do anything funny if they are executed on different threads - * All the mechanics for this would complicate the library and really not solve much of anything while also slowing down - * the library for applications where signals/slots are only used from a single thread - * - * Plus it makes things like adding slots to multiple signals really slow because you have to lock each and every time - * You'd be better off using your own syncronization methods to setup all your singals at once and releasing your lock after - * you're done - */ -#ifndef slimsignals_h -#define slimsignals_h - -#include - -namespace slimsig { - template , class Allocator = std::allocator>> - class signal : private signal_base { - public: - using base = signal_base; - using typename base::return_type; - using typename base::callback; - using typename base::allocator_type; - using typename base::slot; - using typename base::slot_list; - using typename base::list_allocator_type; - using typename base::const_slot_reference; - using typename base::connection_type; - using base::arity; - using base::argument; - // allocator constructor - using base::base; - - // default constructor - signal() : signal(allocator_type()) {}; - using base::emit; - using base::connect; - using base::connect_once; - using base::connect_extended; - using base::disconnect_all; - using base::slot_count; - using base::get_allocator; - using base::empty; - using base::swap; - using base::max_size; - using base::max_depth; - using base::get_depth; - using base::is_running; - using base::remaining_slots; - - }; - template < - class Handler, - class SignalTraits = signal_traits, - class Allocator = std::allocator> - > using signal_t = signal; - -} -#endif diff --git a/rts/lib/slimsig/include/slimsig/tracked_connect.h b/rts/lib/slimsig/include/slimsig/tracked_connect.h deleted file mode 100644 index 46c68bdf70..0000000000 --- a/rts/lib/slimsig/include/slimsig/tracked_connect.h +++ /dev/null @@ -1,131 +0,0 @@ -// -// tracked_connect.h -// slimsig -// -// Created by Christopher Tarquini on 4/22/14. -// -// - -#ifndef slimsig_tracked_connect_h -#define slimsig_tracked_connect_h -#include -#include -#include -#include -#include -#include -namespace slimsig { - template > - class trackable_allocator : private BaseAllocator { - using allocator_traits = std::allocator_traits; - using base = BaseAllocator; - template - using parent_rebind_traits_t = typename allocator_traits::template rebind_traits; - template - using parent_rebind_t = typename parent_rebind_traits_t::allocator_type; - public: - using typename allocator_traits::value_type; - using typename allocator_traits::pointer; - using typename allocator_traits::const_pointer; - using typename allocator_traits::void_pointer; - using typename allocator_traits::const_void_pointer; - using typename allocator_traits::difference_type; - using typename allocator_traits::size_type; - using typename allocator_traits::propagate_on_container_copy_assignment; - using typename allocator_traits::propagate_on_container_move_assignment; - using typename allocator_traits::propagate_on_container_swap; - trackable_allocator() : base() {}; - template - trackable_allocator(const trackable_allocator& other) : base(other), m_observer(other.m_observer) {}; - using base::allocate; - using base::deallocate; - using base::construct; - - template - void destroy(U* p) { - m_observer(p); - allocator_traits::destroy(*this, p); - } - private: - Observer m_observer; - }; - template > - struct trackable_delete { - constexpr trackable_delete() noexcept = default; - template ::value, bool> = true> - trackable_delete(const trackable_delete& other) : m_observer(other.m_observer), m_deleter(m_deleter) {}; - trackable_delete(Observer observer = Observer{}, Deleter deleter = Deleter{}) : m_observer(std::move(observer)), m_deleter(std::move(deleter)){}; - trackable_delete(const trackable_delete&) = default; - trackable_delete(trackable_delete&&) = default; - trackable_delete& operator=(const trackable_delete&) = default; - trackable_delete& operator=(trackable_delete&&) = default; - void operator()(T* ptr) const { - m_observer(ptr); - m_deleter(ptr); - } - const Deleter& get_deleter() const { - return m_deleter; - } - Deleter& get_deleter() { - return m_deleter; - } - const Observer& get_observer() const { - return m_observer; - } - Observer& get_observer() { - return m_observer; - } - private: - Observer m_observer; - Deleter m_deleter; - }; - - template > - using trackable_ptr = std::unique_ptr>; - - template , class TrackableDeleter = trackable_delete, class... Args> - std::shared_ptr make_trackable(TrackableDeleter deleter, Args&&... args) { - return std::shared_ptr ( deleter, T{std::forward(args)...} ); - } - template , class TrackableDeleter = trackable_delete, class... Args> - std::shared_ptr make_trackable(Observer observer, Args&&... args) { - return std::shared_ptr ( TrackableDeleter { observer }, T{std::forward(args)...} ); - } - template , class TrackableDeleter = trackable_delete, class... Args> - std::shared_ptr make_trackable(Observer observer, Deleter deleter, Args&&... args) { - return std::shared_ptr ( TrackableDeleter { observer, deleter }, T{std::forward(args)...} ); - } - template , class TrackableAllocator = trackable_allocator, class... Args> - std::shared_ptr allocate_trackable(TrackableAllocator allocator, Args&&... args) { - return std::allocate_shared(allocator, std::forward(args)...); - } - template , class TrackableAllocator = trackable_allocator, class... Args> - std::shared_ptr allocate_trackable(Observer observer, Args&&... args) { - return std::allocate_shared(TrackableAllocator {observer}, std::forward(args)...); - } - template , class TrackableAllocator = trackable_allocator, class... Args> - std::shared_ptr allocate_trackable(Observer observer, Allocator allocator, Args&&... args) { - return std::allocate_shared(TrackableAllocator {observer, allocator}, std::forward(args)...); - } - - - template - class trackable_lock { - public: - using weak_ptr_type = std::weak_ptr; - trackable_lock(std::vector> trackable_objects) : m_tracking(std::move(trackable_objects)) {}; - trackable_lock(std::initializer_list> trackable_list) : m_tracking{std::move(trackable_list)} {} - /*template - weak_ptr(Iterator begin, Iterator end) : m_tracking(begin, end) {}*/ - - bool try_lock() { - m_locked.reserve(m_tracking.size()); - - } - private: - std::vector> m_tracking; - std::vector> m_locked; - }; -} - -#endif