1
0
mirror of https://github.com/wqking/eventpp.git synced 2025-01-15 01:29:08 +08:00
eventpp/tests/tutorial/tutorial_anydata.cpp

214 lines
7.0 KiB
C++
Raw Normal View History

2023-04-30 08:23:54 +08:00
// eventpp library
// Copyright (C) 2018 Wang Qi (wqking)
// Github: https://github.com/wqking/eventpp
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Include the head
#include "eventpp/utilities/anydata.h"
#include "eventpp/eventqueue.h"
#include "tutorial.h"
#include <iostream>
namespace {
// In the tutorials here, we define an event class hierarchy, Event is the base class.
// Define the event types
enum class EventType
{
// for MouseEvent
mouse,
// for KeyEvent
key,
// for MessageEvent
message,
// For a simple std::string event which is not derived from Event
text,
};
class Event
{
public:
Event() {
}
};
class MouseEvent : public Event
{
public:
MouseEvent(const int x, const int y)
: x(x), y(y)
{
}
int getX() const { return x; }
int getY() const { return y; }
private:
int x;
int y;
};
class KeyEvent : public Event
{
public:
explicit KeyEvent(const int key)
: key(key)
{
}
int getKey() const { return key; }
private:
int key;
};
class MessageEvent : public Event
{
public:
explicit MessageEvent(const std::string & message)
: message(message) {
}
std::string getMessage() const { return message; }
private:
std::string message;
};
// eventMaxSize is the maximum size of all possible types to use in AnyData, it's used to construct AnyData.
constexpr std::size_t eventMaxSize = eventpp::maxSizeOf<
Event,
KeyEvent,
MouseEvent,
MessageEvent,
std::string
>();
2023-05-16 10:56:35 +08:00
void onMessageEvent(const MessageEvent & e)
{
std::cout << "Received MessageEvent in free function, message="
<< e.getMessage() << std::endl;
}
2023-04-30 08:23:54 +08:00
TEST_CASE("AnyData tutorial 1, basic")
{
std::cout << std::endl << "AnyData tutorial 1, basic" << std::endl;
eventpp::EventQueue<EventType, void (const eventpp::AnyData<eventMaxSize> &)> queue;
// Append a listener. Note the listener argument is `const Event &` which is different with the prototype in
// the queue definition. This works since `AnyData` can convert to any data type automatically.
2023-04-30 08:23:54 +08:00
queue.appendListener(EventType::key, [](const Event & e) {
std::cout << "Received KeyEvent, key="
<< static_cast<const KeyEvent &>(e).getKey() << std::endl;
});
queue.appendListener(EventType::mouse, [](const Event & e) {
std::cout << "Received MouseEvent, x=" << static_cast<const MouseEvent &>(e).getX()
<< " y=" << static_cast<const MouseEvent &>(e).getY() << std::endl;
});
2023-05-16 10:56:35 +08:00
// Even more convenient, the argument type can be the concrete class such as MessageEvent,
// but be sure the listener only receive MessageEvent. If it also receives MouseEvent,
// we can expect crash.
queue.appendListener(EventType::message, [](const MessageEvent & e) {
2023-04-30 08:23:54 +08:00
std::cout << "Received MessageEvent, message="
2023-05-16 10:56:35 +08:00
<< e.getMessage() << std::endl;
2023-04-30 08:23:54 +08:00
});
2023-05-16 10:56:35 +08:00
// Not only lambda, we can also use free function, or member function as the listener.
queue.appendListener(EventType::message, &onMessageEvent);
2023-04-30 08:23:54 +08:00
// Put events into the queue. Any data type, such as KeyEvent, MouseEvent, can be put
// as long as the data size doesn't exceed eventMaxSize.
queue.enqueue(EventType::key, KeyEvent(255));
queue.enqueue(EventType::mouse, MouseEvent(3, 5));
queue.enqueue(EventType::message, MessageEvent("Hello, AnyData"));
queue.process();
}
TEST_CASE("AnyData tutorial 2, unrelated data")
{
std::cout << std::endl << "AnyData tutorial 2, unrelated data" << std::endl;
// It's possible to send event with data that doesn't have the same base class, such as Event.
// To do so, the listener prototype must be `const void *` instead of `const Event &` in previous tutorial.
struct Policies {
using Callback = std::function<void (const EventType, const void *)>;
};
eventpp::EventQueue<
EventType,
void (const EventType, const eventpp::AnyData<eventMaxSize> &),
Policies> queue;
queue.appendListener(EventType::key, [](const EventType type, const void * e) {
REQUIRE(type == EventType::key);
std::cout << "Received KeyEvent, key=" << static_cast<const KeyEvent *>(e)->getKey() << std::endl;
});
queue.appendListener(EventType::mouse, [](const EventType type, const void * e) {
REQUIRE(type == EventType::mouse);
std::cout << "Received MouseEvent, x=" << static_cast<const MouseEvent *>(e)->getX()
<< " y=" << static_cast<const MouseEvent *>(e)->getY() << std::endl;
});
queue.appendListener(EventType::message, [](const EventType type, const void * e) {
REQUIRE(type == EventType::message);
std::cout << "Received MessageEvent, message="
<< static_cast<const MessageEvent *>(e)->getMessage() << std::endl;
});
queue.appendListener(EventType::text, [](const EventType type, const void * e) {
REQUIRE(type == EventType::text);
std::cout << "Received text event, text=" << *static_cast<const std::string *>(e) << std::endl;
});
// Send events
queue.enqueue(EventType::key, KeyEvent(255));
queue.enqueue(EventType::mouse, MouseEvent(3, 5));
queue.enqueue(EventType::message, MessageEvent("Hello, AnyData"));
// Send a std::string as the event data which doesn't derive from Event.
queue.enqueue(EventType::text, std::string("This is a text"));
queue.process();
}
TEST_CASE("AnyData tutorial 3, use AnyData in listener")
{
std::cout << std::endl << "AnyData tutorial 3, use AnyData in listener" << std::endl;
using MyData = eventpp::AnyData<eventMaxSize>;
eventpp::EventQueue<EventType, void (const EventType, const MyData &)> queue;
queue.appendListener(EventType::key, [](const EventType type, const MyData & e) {
REQUIRE(type == EventType::key);
REQUIRE(e.isType<KeyEvent>());
std::cout << "Received KeyEvent, key=" << e.get<KeyEvent>().getKey() << std::endl;
});
queue.appendListener(EventType::mouse, [](const EventType type, const MyData & e) {
REQUIRE(type == EventType::mouse);
REQUIRE(e.isType<MouseEvent>());
std::cout << "Received MouseEvent, x=" << e.get<MouseEvent>().getX()
<< " y=" << e.get<MouseEvent>().getY() << std::endl;
});
queue.appendListener(EventType::message, [](const EventType type, const MyData & e) {
REQUIRE(type == EventType::message);
REQUIRE(e.isType<MessageEvent>());
std::cout << "Received MessageEvent, message=" << e.get<MessageEvent>().getMessage() << std::endl;
});
queue.appendListener(EventType::text, [](const EventType type, const MyData & e) {
REQUIRE(type == EventType::text);
REQUIRE(e.isType<std::string>());
std::cout << "Received text event, text=" << e.get<std::string>() << std::endl;
});
queue.enqueue(EventType::key, KeyEvent(255));
queue.enqueue(EventType::mouse, MouseEvent(3, 5));
queue.enqueue(EventType::message, MessageEvent("Hello, AnyData"));
queue.enqueue(EventType::text, std::string("This is a text"));
queue.process();
}
} // namespace