[ox/event] Add Event package
This commit is contained in:
parent
b27d6671fc
commit
950712b85e
1
deps/ox/src/ox/CMakeLists.txt
vendored
1
deps/ox/src/ox/CMakeLists.txt
vendored
@ -3,6 +3,7 @@ if(OX_USE_STDLIB)
|
|||||||
endif()
|
endif()
|
||||||
add_subdirectory(clargs)
|
add_subdirectory(clargs)
|
||||||
add_subdirectory(claw)
|
add_subdirectory(claw)
|
||||||
|
add_subdirectory(event)
|
||||||
add_subdirectory(fs)
|
add_subdirectory(fs)
|
||||||
add_subdirectory(mc)
|
add_subdirectory(mc)
|
||||||
add_subdirectory(model)
|
add_subdirectory(model)
|
||||||
|
47
deps/ox/src/ox/event/CMakeLists.txt
vendored
Normal file
47
deps/ox/src/ox/event/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
add_library(
|
||||||
|
OxEvent
|
||||||
|
signal.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
target_compile_options(OxEvent PRIVATE -Wsign-conversion)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT OX_BARE_METAL)
|
||||||
|
set_property(
|
||||||
|
TARGET
|
||||||
|
OxEvent
|
||||||
|
PROPERTY
|
||||||
|
POSITION_INDEPENDENT_CODE ON
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(
|
||||||
|
OxEvent PUBLIC
|
||||||
|
$<$<BOOL:${OX_USE_STDLIB}>:OX_USE_STDLIB>
|
||||||
|
$<$<BOOL:${OX_NODEBUG}>:OX_NODEBUG>
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
OxEvent PUBLIC
|
||||||
|
$<$<BOOL:${OX_USE_STDLIB}>:dl>
|
||||||
|
$<$<CXX_COMPILER_ID:GNU>:gcc>
|
||||||
|
OxStd
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
event.hpp
|
||||||
|
signal.hpp
|
||||||
|
DESTINATION
|
||||||
|
include/ox/event
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS OxEvent
|
||||||
|
LIBRARY DESTINATION lib/ox
|
||||||
|
ARCHIVE DESTINATION lib/ox
|
||||||
|
)
|
||||||
|
|
||||||
|
if(OX_RUN_TESTS)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
11
deps/ox/src/ox/event/event.hpp
vendored
Normal file
11
deps/ox/src/ox/event/event.hpp
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2021 gary@drinkingtea.net
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "signal.hpp"
|
19
deps/ox/src/ox/event/signal.cpp
vendored
Normal file
19
deps/ox/src/ox/event/signal.cpp
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2021 gary@drinkingtea.net
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "signal.hpp"
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
template class Signal<Error(const SignalHandler*)>;
|
||||||
|
|
||||||
|
SignalHandler::~SignalHandler() noexcept {
|
||||||
|
destruction.emit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
189
deps/ox/src/ox/event/signal.hpp
vendored
Normal file
189
deps/ox/src/ox/event/signal.hpp
vendored
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2021 gary@drinkingtea.net
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/std/error.hpp>
|
||||||
|
#include <ox/std/memory.hpp>
|
||||||
|
#include <ox/std/vector.hpp>
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
class SignalHandler;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Signal;
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
class Signal<Error(Args...)> {
|
||||||
|
protected:
|
||||||
|
struct BaseSlot {
|
||||||
|
virtual ~BaseSlot() = default;
|
||||||
|
virtual Error call(Args...) noexcept = 0;
|
||||||
|
virtual void cleanup(Signal*) noexcept {}
|
||||||
|
virtual const void *receiver() noexcept { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunctionSlot: public BaseSlot {
|
||||||
|
Error (*f)(Args...);
|
||||||
|
|
||||||
|
explicit FunctionSlot(Error (*f)(Args...)) noexcept {
|
||||||
|
this->f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error call(Args... args) noexcept final {
|
||||||
|
return f(args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename Method>
|
||||||
|
struct MethodSlot: public BaseSlot {
|
||||||
|
T m_receiver = nullptr;
|
||||||
|
Method m_methodPtr;
|
||||||
|
|
||||||
|
MethodSlot(T receiver, Method methodPtr) {
|
||||||
|
m_receiver = receiver;
|
||||||
|
m_methodPtr = methodPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error call(Args... args) noexcept final {
|
||||||
|
return (m_receiver->*(m_methodPtr))(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup(Signal *signal) noexcept final {
|
||||||
|
oxIgnoreError(m_receiver->destruction.disconnectSignal(signal));
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *receiver() noexcept final {
|
||||||
|
return m_receiver;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename SignalT, typename Method>
|
||||||
|
struct SignalMethodSlot: public BaseSlot {
|
||||||
|
const SignalT *m_receiver = nullptr;
|
||||||
|
Method m_methodPtr;
|
||||||
|
|
||||||
|
SignalMethodSlot(const SignalT *receiver, Method methodPtr) {
|
||||||
|
m_receiver = receiver;
|
||||||
|
m_methodPtr = methodPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error call(Args... args) noexcept final {
|
||||||
|
return (m_receiver->*(m_methodPtr))(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup(Signal*) noexcept final {
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *receiver() noexcept final {
|
||||||
|
return m_receiver;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mutable Vector<UniquePtr<BaseSlot>> m_slots;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~Signal() noexcept;
|
||||||
|
|
||||||
|
void connect(Error(*f)(Args...)) const noexcept;
|
||||||
|
|
||||||
|
template<typename T, typename Method>
|
||||||
|
void connect(const T *receiver, Method methodPtr) const noexcept;
|
||||||
|
|
||||||
|
template<typename T, typename Method>
|
||||||
|
void connect(T *receiver, Method methodPtr) const noexcept;
|
||||||
|
|
||||||
|
template<class... SubArgs, typename Method>
|
||||||
|
void connect(const Signal<SubArgs...> *receiver, Method methodPtr) const noexcept;
|
||||||
|
|
||||||
|
template<class... SubArgs>
|
||||||
|
Error disconnectSignal(const Signal<SubArgs...> *receiver) const noexcept;
|
||||||
|
|
||||||
|
Error disconnectObject(const void *receiver) const noexcept;
|
||||||
|
|
||||||
|
void emit(Args... args) noexcept;
|
||||||
|
|
||||||
|
Error emitCheckError(Args... args) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern template class Signal<Error(const SignalHandler*)>;
|
||||||
|
|
||||||
|
class SignalHandler {
|
||||||
|
public:
|
||||||
|
Signal<Error(const SignalHandler*)> destruction;
|
||||||
|
|
||||||
|
virtual ~SignalHandler() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
Signal<Error(Args...)>::~Signal() noexcept {
|
||||||
|
for (auto &slot : m_slots) {
|
||||||
|
slot->cleanup(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void Signal<Error(Args...)>::connect(Error(*f)(Args...)) const noexcept {
|
||||||
|
m_slots.emplace_back(new FunctionSlot(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
template<typename T, typename Method>
|
||||||
|
void Signal<Error(Args...)>::connect(const T *receiver, Method methodPtr) const noexcept {
|
||||||
|
receiver->destruction.connect(this, &Signal<Error(Args...)>::disconnectObject);
|
||||||
|
m_slots.emplace_back(new MethodSlot<const T*, Method>(receiver, methodPtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
template<typename T, typename Method>
|
||||||
|
void Signal<Error(Args...)>::connect(T *receiver, Method methodPtr) const noexcept {
|
||||||
|
receiver->destruction.connect(this, &Signal<Error(Args...)>::disconnectObject);
|
||||||
|
m_slots.emplace_back(new MethodSlot<T*, Method>(receiver, methodPtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
template<class... SubArgs, typename Method>
|
||||||
|
void Signal<Error(Args...)>::connect(const Signal<SubArgs...> *receiver, Method methodPtr) const noexcept {
|
||||||
|
m_slots.emplace_back(new SignalMethodSlot<Signal<SubArgs...>, Method>(receiver, methodPtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
template<class... SubArgs>
|
||||||
|
Error Signal<Error(Args...)>::disconnectSignal(const Signal<SubArgs...> *receiver) const noexcept {
|
||||||
|
return disconnectObject(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
Error Signal<Error(Args...)>::disconnectObject(const void *signal) const noexcept {
|
||||||
|
for (auto i = 0u; i < m_slots.size(); ++i) {
|
||||||
|
const auto &slot = m_slots[i];
|
||||||
|
if (slot->receiver() == signal) {
|
||||||
|
oxReturnError(m_slots.erase(i));
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OxError(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void Signal<Error(Args...)>::emit(Args... args) noexcept {
|
||||||
|
for (auto &f : m_slots) {
|
||||||
|
oxIgnoreError(f->call(args...));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
Error Signal<Error(Args...)>::emitCheckError(Args... args) noexcept {
|
||||||
|
for (auto &f : m_slots) {
|
||||||
|
oxReturnError(f->call(args...));
|
||||||
|
}
|
||||||
|
return OxError(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
deps/ox/src/ox/event/test/CMakeLists.txt
vendored
Normal file
10
deps/ox/src/ox/event/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
EventTest
|
||||||
|
tests.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(EventTest OxEvent)
|
||||||
|
|
||||||
|
add_test("[ox/event] Test 1" EventTest "test1")
|
50
deps/ox/src/ox/event/test/tests.cpp
vendored
Normal file
50
deps/ox/src/ox/event/test/tests.cpp
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 - 2021 gary@drinkingtea.net
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef NDEBUG
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
#include <ox/event/signal.hpp>
|
||||||
|
#include <ox/std/std.hpp>
|
||||||
|
|
||||||
|
struct TestStruct: public ox::SignalHandler {
|
||||||
|
int value = 0;
|
||||||
|
ox::Error method(int i) noexcept {
|
||||||
|
value = i;
|
||||||
|
return OxError(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::string, std::function<ox::Error()>> tests = {
|
||||||
|
{
|
||||||
|
"test1",
|
||||||
|
[] {
|
||||||
|
ox::Signal<ox::Error(int)> signal;
|
||||||
|
signal.connect([](int i) -> ox::Error {
|
||||||
|
return OxError(i != 5);
|
||||||
|
});
|
||||||
|
TestStruct ts;
|
||||||
|
signal.connect(&ts, &TestStruct::method);
|
||||||
|
oxReturnError(signal.emitCheckError(5));
|
||||||
|
oxReturnError(OxError(ts.value != 5));
|
||||||
|
return OxError(0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, const char **args) {
|
||||||
|
if (argc > 1) {
|
||||||
|
auto testName = args[1];
|
||||||
|
if (tests.find(testName) != tests.end()) {
|
||||||
|
oxAssert(tests[testName](), "Test returned Error");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user