Files
gcc-reflection/gcc/pub-sub.cc
David Malcolm b34dad6d18 Add pub-sub.{h,cc}
This patch introduces a publish/subscribe mechanism, allowing for
loosely-coupled senders and receivers, with strongly-typed messages
passing between them.  For example, a GCC subsystem could publish
messages about events, and a plugin could subscribe to them.

An example can be seen in the selftests.

gcc/ChangeLog:
	* Makefile.in (OBJS-libcommon): Add pub-sub.o.
	* pub-sub.cc: New file.
	* pub-sub.h: New file.
	* selftest-run-tests.cc (selftest::run_tests): Call
	selftest::pub_sub_cc_tests.
	* selftest.h (selftest::pub_sub_cc_tests): New decl.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
2026-01-09 15:54:15 -05:00

139 lines
3.3 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Loosely-coupled notifications via the Publish-Subscribe pattern.
Copyright (C) 2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#define INCLUDE_LIST
#define INCLUDE_STRING
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "pub-sub.h"
#if CHECKING_P
#include "selftest.h"
namespace selftest {
/* Selftests. */
// A topic for use in selftests
namespace snafu {
struct paper_jam {};
struct out_of_paper
{
int tray;
};
struct ink_low
{
std::string color;
};
struct subscriber
{
virtual void on_message (const paper_jam &m) = 0;
virtual void on_message (const out_of_paper &m) = 0;
virtual void on_message (const ink_low &m) = 0;
};
} // namespace snafu
static void
test_example ()
{
struct logger : public snafu::subscriber
{
void on_message (const snafu::paper_jam &) final override
{
m_log += "paper jam\n";
}
void on_message (const snafu::out_of_paper &m) final override
{
m_log += "out of paper (tray " + std::to_string (m.tray) + ")\n";
}
void on_message (const snafu::ink_low &m) final override
{
m_log += "ink low: " + m.color + "\n";
}
std::string m_log;
};
pub_sub::channel<snafu::subscriber> printer_a;
pub_sub::channel<snafu::subscriber> printer_b;
pub_sub::channel<snafu::subscriber> printer_c;
// No subscribers yet
ASSERT_EQ (printer_a.get_if_active (), nullptr);
ASSERT_EQ (printer_b.get_if_active (), nullptr);
ASSERT_EQ (printer_c.get_if_active (), nullptr);
// Subscribers to individual channels
logger log_a;
logger log_b;
logger log_c;
printer_a.add_subscriber (log_a);
printer_b.add_subscriber (log_b);
printer_c.add_subscriber (log_c);
// A subscriber to all channels
logger log_all;
printer_a.add_subscriber (log_all);
printer_b.add_subscriber (log_all);
printer_c.add_subscriber (log_all);
// The channels now have subscribers
ASSERT_EQ (printer_a.get_if_active (), &printer_a);
ASSERT_EQ (printer_b.get_if_active (), &printer_b);
ASSERT_EQ (printer_c.get_if_active (), &printer_c);
// Publish a message to each channel
printer_a.publish (snafu::paper_jam {});
printer_b.publish (snafu::out_of_paper {1});
printer_c.publish (snafu::ink_low {"cyan"});
// Verify that the subscribers got the messages they were meant to
ASSERT_EQ (log_a.m_log, "paper jam\n");
ASSERT_EQ (log_b.m_log, "out of paper (tray 1)\n");
ASSERT_EQ (log_c.m_log, "ink low: cyan\n");
ASSERT_EQ (log_all.m_log,
"paper jam\n"
"out of paper (tray 1)\n"
"ink low: cyan\n");
}
/* Run all of the selftests within this file. */
void
pub_sub_cc_tests ()
{
test_example ();
}
} // namespace selftest
#endif /* #if CHECKING_P */