Mercurial > hg > svcore
comparison base/ById.h @ 1764:0678bf772f82 by-id
Doc
author | Chris Cannam |
---|---|
date | Wed, 17 Jul 2019 12:57:33 +0100 |
parents | d954dfccd922 |
children | 7faa08747f5e |
comparison
equal
deleted
inserted
replaced
1763:d1e2062cbdec | 1764:0678bf772f82 |
---|---|
25 #include <QMutex> | 25 #include <QMutex> |
26 #include <QString> | 26 #include <QString> |
27 | 27 |
28 #include "XmlExportable.h" | 28 #include "XmlExportable.h" |
29 | 29 |
30 //!!! todo: docs | 30 /* |
31 | 31 * ById - central pool of objects to be retrieved by persistent id. |
32 //!!! further possibilities: | 32 * |
33 // | 33 * This is a pretty simple mechanism for obtaining safe "borrowed" |
34 // - get() returns a pointer wrapper that cannot be shared/copied | 34 * references to shared objects, including across threads, based on an |
35 // again by the caller (except by the usual C++ trickery) | 35 * object ID. |
36 // | 36 * |
37 // also to do: review how often we are calling getAs<...> when we | 37 * A class (call it C) inherits WithTypedId<C>. This produces a type |
38 // could just be using get | 38 * C::Id containing a numerical id. Each instance of C (or subclass |
39 | 39 * thereof) has an internal id of type C::Id whose value is unique |
40 //!!! NB we still haven't solved the problem of what to do for a | 40 * among all ids ever possessed by any instances of all classes that |
41 //!!! user-initiated cancel of a transform | 41 * use this id mechanism (within a single run of the program). |
42 * | |
43 * Then we have a static store of type TypedById<C, C::Id>. This holds | |
44 * a set of heap-allocated C objects (or subclass thereof) and hands | |
45 * out shared_ptr references to them when queried by id. The | |
46 * application calls add() to pass an object to the store (which takes | |
47 * ownership of it), and the application calls release() when it | |
48 * thinks it has finished with an object, to request the store to | |
49 * delete it. | |
50 * | |
51 * Note that an object's id can't (without shenanigans) be queried | |
52 * directly from that object - it is returned when the object is added | |
53 * to a ById store. So if you have an object id, you know that the | |
54 * object must have been added to a store at some point. | |
55 * | |
56 * The goal is to improve code that would previously have retained a | |
57 * bare pointer to a heap-allocated object that it did not own. For | |
58 * example, in Sonic Visualiser we have a Model hierarchy of complex | |
59 * mutable objects, and any given model may be referred to by many | |
60 * different layers, transforms (as both source and target) etc. Using | |
61 * bare pointers for those references means that we need everything to | |
62 * be notified (and act properly on the notification) if a model is | |
63 * about to be deleted. Using a Model::Id instead gives the code a | |
64 * guarantee: if the model has been deleted since you last looked at | |
65 * it, then the ById store will return a null shared_ptr from its | |
66 * get() function for that id; but if it returns a non-null | |
67 * shared_ptr, then the object being pointed to can't be deleted while | |
68 * that shared_ptr is in scope. | |
69 * | |
70 * Example: | |
71 * | |
72 * class Thing : public WithTypedId<Thing> { Thing(int x) { } }; | |
73 * typedef TypedById<Thing, Thing::Id> ThingById; | |
74 * | |
75 * // application creates a new Thing | |
76 * // ... | |
77 * auto thing = std::make_shared<Thing>(10); | |
78 * auto thingId = ThingById::add(thing); | |
79 * | |
80 * // application then passes thingId to something else, without | |
81 * // storing the shared_ptr anywhere - the ById store manages that | |
82 * | |
83 * // code elsewhere now has the thingId, and needs to use the Thing | |
84 * // ... | |
85 * void doSomething() { | |
86 * auto thing = ThingById::get(m_thingId); | |
87 * if (!thing) { // the Thing has been deleted, stop acting on it | |
88 * return; // (this may be an error or it may be unexceptional) | |
89 * } | |
90 * // now we have a guarantee that the thing ptr will be valid | |
91 * // until it goes out of scope when doSomething returns | |
92 * } | |
93 * | |
94 * // application wants to be rid of the Thing | |
95 * ThingById::release(thingId); | |
96 */ | |
97 | |
98 //!!! to do: review how often we are calling getAs<...> when we could | |
99 // just be using get | |
42 | 100 |
43 struct IdAlloc { | 101 struct IdAlloc { |
44 | 102 |
45 // The value NO_ID (-1) is never allocated | 103 // The value NO_ID (-1) is never allocated |
46 static const int NO_ID = -1; | 104 static const int NO_ID = -1; |