16#include <unordered_map>
39template <
typename Accessor>
class access_tracker {
40 std::shared_ptr<context> ctx;
42 std::function<Accessor(access_tracker &)> accessor_factory;
47 explicit access_tracker(std::shared_ptr<context> context, std::string name)
48 : ctx(std::move(context)), name(std::move(name)) {}
64 auto operator=(access_tracker
const &) =
delete;
68 auto operator=(access_tracker &&rhs)
noexcept -> access_tracker &;
85 assert(not accessor_factory);
86 accessor_factory = std::move(factory);
113class context :
public std::enable_shared_from_this<context> {
119 std::unordered_map<std::string, std::any> trackers;
121 template <
typename Accessor>
friend class access_tracker;
123 template <
typename Accessor>
124 void update_tracker_address(std::string
const &name,
125 access_tracker<Accessor> *ptr) {
127 *std::any_cast<access_tracker<Accessor> *>(&trackers.at(name)) = ptr;
135 context(context
const &) =
delete;
136 auto operator=(context
const &) =
delete;
137 context(context &&) =
delete;
138 auto operator=(context &&) =
delete;
139 ~context() =
default;
145 static auto create() -> std::shared_ptr<context> {
146 return std::shared_ptr<context>(
new context());
158 template <
typename Accessor>
159 auto tracker(std::string name) -> access_tracker<Accessor> {
160 if (trackers.count(name) != 0) {
161 throw std::logic_error(
162 "cannot create tracker for existing name: " + name);
165 access_tracker<Accessor>(shared_from_this(), std::move(name));
166 trackers.insert({ret.name, std::any(&ret)});
180 template <
typename Accessor>
181 auto access(std::string
const &name) -> Accessor {
183 std::any_cast<access_tracker<Accessor> *>(trackers.at(name));
184 if (tracker_ptr ==
nullptr)
185 throw std::logic_error(
"cannot access destroyed object: " + name);
186 return tracker_ptr->accessor_factory(*tracker_ptr);
195template <
typename Accessor>
197 : ctx(std::move(other.ctx)), name(std::move(other.name)),
198 accessor_factory(std::move(other.accessor_factory)) {
200 ctx->update_tracker_address(name,
this);
203template <
typename Accessor>
206 ctx = std::move(rhs.ctx);
207 name = std::move(rhs.name);
208 accessor_factory = std::move(rhs.accessor_factory);
210 ctx->update_tracker_address(name,
this);
216 ctx->update_tracker_address<Accessor>(name,
nullptr);
225#if defined(__GNUC__) || defined(__clang__)
226#define LIBTCSPC_INTERNAL_DISABLE_OFFSETOF_WARNING \
227 _Pragma("GCC diagnostic push"); \
228 _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"")
229#define LIBTCSPC_INTERNAL_POP_OFFSETOF_WARNING _Pragma("GCC diagnostic pop")
231#define LIBTCSPC_INTERNAL_DISABLE_OFFSETOF_WARNING
232#define LIBTCSPC_INTERNAL_POP_OFFSETOF_WARNING
255#define LIBTCSPC_OBJECT_FROM_TRACKER(obj_type, tracker_field_name, tracker) \
256 std::invoke([&tracker]() { \
257 LIBTCSPC_INTERNAL_DISABLE_OFFSETOF_WARNING; \
258 return reinterpret_cast<std::add_pointer_t<obj_type>>( \
259 reinterpret_cast<std::byte *>(&(tracker)) - \
260 offsetof(obj_type, tracker_field_name)); \
261 LIBTCSPC_INTERNAL_POP_OFFSETOF_WARNING; \
Tracker that mediates access to objects via a tcspc::context.
Definition context.hpp:39
access_tracker()=default
Construct an empty tracker.
void register_accessor_factory(F factory)
Register an accessor factory with this tracker's context.
Definition context.hpp:83
Context for enabling access to objects after they have been incorporated into a processing graph.
Definition context.hpp:113
auto access(std::string const &name) -> Accessor
Obtain an accessor for the named object.
Definition context.hpp:181
static auto create() -> std::shared_ptr< context >
Create an instance.
Definition context.hpp:145
auto tracker(std::string name) -> access_tracker< Accessor >
Obtain a tracker for an object with the given name.
Definition context.hpp:159
libtcspc namespace.
Definition acquire.hpp:30