2013-10-24 17:44:27 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2013 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SkMessageBus_DEFINED
|
|
|
|
#define SkMessageBus_DEFINED
|
|
|
|
|
2018-07-16 21:44:06 +00:00
|
|
|
#include "../private/SkNoncopyable.h"
|
2015-07-07 19:21:21 +00:00
|
|
|
#include "SkMutex.h"
|
2016-05-05 23:05:56 +00:00
|
|
|
#include "SkOnce.h"
|
2015-02-06 19:54:28 +00:00
|
|
|
#include "SkTArray.h"
|
2013-10-24 17:44:27 +00:00
|
|
|
#include "SkTDArray.h"
|
|
|
|
#include "SkTypes.h"
|
|
|
|
|
2018-07-11 19:58:57 +00:00
|
|
|
/**
|
|
|
|
* Message must implement bool Message::shouldSend(uint32_t inboxID) const. Perhaps someday we
|
|
|
|
* can use std::experimental::is_detected to avoid this requirement by sending to all inboxes when
|
|
|
|
* the method is not detected on Message.
|
|
|
|
*/
|
2013-10-24 17:44:27 +00:00
|
|
|
template <typename Message>
|
|
|
|
class SkMessageBus : SkNoncopyable {
|
|
|
|
public:
|
2018-07-11 19:58:57 +00:00
|
|
|
// Post a message to be received by Inboxes for this Message type. Checks
|
|
|
|
// Message::shouldSend() for each inbox. Threadsafe.
|
|
|
|
static void Post(const Message& m);
|
2013-10-24 17:44:27 +00:00
|
|
|
|
|
|
|
class Inbox {
|
|
|
|
public:
|
2017-12-14 18:00:05 +00:00
|
|
|
Inbox(uint32_t uniqueID = SK_InvalidUniqueID);
|
2013-10-24 17:44:27 +00:00
|
|
|
~Inbox();
|
|
|
|
|
|
|
|
// Overwrite out with all the messages we've received since the last call. Threadsafe.
|
2015-02-06 19:54:28 +00:00
|
|
|
void poll(SkTArray<Message>* out);
|
2013-10-24 17:44:27 +00:00
|
|
|
|
|
|
|
private:
|
2015-02-06 19:54:28 +00:00
|
|
|
SkTArray<Message> fMessages;
|
2013-10-24 17:44:27 +00:00
|
|
|
SkMutex fMessagesMutex;
|
2017-12-14 18:00:05 +00:00
|
|
|
uint32_t fUniqueID;
|
2013-10-24 17:44:27 +00:00
|
|
|
|
|
|
|
friend class SkMessageBus;
|
|
|
|
void receive(const Message& m); // SkMessageBus is a friend only to call this.
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
SkMessageBus();
|
|
|
|
static SkMessageBus* Get();
|
2014-10-13 20:17:56 +00:00
|
|
|
|
2013-10-24 17:44:27 +00:00
|
|
|
SkTDArray<Inbox*> fInboxes;
|
|
|
|
SkMutex fInboxesMutex;
|
|
|
|
};
|
|
|
|
|
2014-01-15 23:09:01 +00:00
|
|
|
// This must go in a single .cpp file, not some .h, or we risk creating more than one global
|
2014-10-13 20:17:56 +00:00
|
|
|
// SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile.
|
2015-09-09 16:09:53 +00:00
|
|
|
#define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \
|
|
|
|
template <> \
|
|
|
|
SkMessageBus<Message>* SkMessageBus<Message>::Get() { \
|
2016-05-05 23:05:56 +00:00
|
|
|
static SkOnce once; \
|
|
|
|
static SkMessageBus<Message>* bus; \
|
|
|
|
once([] { bus = new SkMessageBus<Message>(); }); \
|
|
|
|
return bus; \
|
2014-01-15 23:09:01 +00:00
|
|
|
}
|
|
|
|
|
2013-10-24 17:44:27 +00:00
|
|
|
// ----------------------- Implementation of SkMessageBus::Inbox -----------------------
|
|
|
|
|
|
|
|
template<typename Message>
|
2017-12-14 18:00:05 +00:00
|
|
|
SkMessageBus<Message>::Inbox::Inbox(uint32_t uniqueID) : fUniqueID(uniqueID) {
|
2013-10-24 17:44:27 +00:00
|
|
|
// Register ourselves with the corresponding message bus.
|
|
|
|
SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
|
|
|
|
SkAutoMutexAcquire lock(bus->fInboxesMutex);
|
2018-08-08 15:23:41 +00:00
|
|
|
bus->fInboxes.push_back(this);
|
2013-10-24 17:44:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Message>
|
|
|
|
SkMessageBus<Message>::Inbox::~Inbox() {
|
|
|
|
// Remove ourselves from the corresponding message bus.
|
|
|
|
SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
|
|
|
|
SkAutoMutexAcquire lock(bus->fInboxesMutex);
|
|
|
|
// This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter.
|
|
|
|
for (int i = 0; i < bus->fInboxes.count(); i++) {
|
|
|
|
if (this == bus->fInboxes[i]) {
|
|
|
|
bus->fInboxes.removeShuffle(i);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Message>
|
|
|
|
void SkMessageBus<Message>::Inbox::receive(const Message& m) {
|
|
|
|
SkAutoMutexAcquire lock(fMessagesMutex);
|
2015-02-06 19:54:28 +00:00
|
|
|
fMessages.push_back(m);
|
2013-10-24 17:44:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Message>
|
2015-02-06 19:54:28 +00:00
|
|
|
void SkMessageBus<Message>::Inbox::poll(SkTArray<Message>* messages) {
|
2014-09-05 20:34:00 +00:00
|
|
|
SkASSERT(messages);
|
2013-10-24 17:44:27 +00:00
|
|
|
messages->reset();
|
|
|
|
SkAutoMutexAcquire lock(fMessagesMutex);
|
2018-06-18 19:11:00 +00:00
|
|
|
fMessages.swap(*messages);
|
2013-10-24 17:44:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------- Implementation of SkMessageBus -----------------------
|
|
|
|
|
|
|
|
template <typename Message>
|
|
|
|
SkMessageBus<Message>::SkMessageBus() {}
|
|
|
|
|
|
|
|
template <typename Message>
|
2018-07-11 19:58:57 +00:00
|
|
|
/*static*/ void SkMessageBus<Message>::Post(const Message& m) {
|
2013-10-24 17:44:27 +00:00
|
|
|
SkMessageBus<Message>* bus = SkMessageBus<Message>::Get();
|
|
|
|
SkAutoMutexAcquire lock(bus->fInboxesMutex);
|
|
|
|
for (int i = 0; i < bus->fInboxes.count(); i++) {
|
2018-07-11 19:58:57 +00:00
|
|
|
if (m.shouldSend(bus->fInboxes[i]->fUniqueID)) {
|
2017-12-14 18:00:05 +00:00
|
|
|
bus->fInboxes[i]->receive(m);
|
|
|
|
}
|
2013-10-24 17:44:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // SkMessageBus_DEFINED
|