Skip to content

Commit e84f8d9

Browse files
committed
Merge pull request #287 from leapmotion/feat-autopacketgraph
AutoPacketGraph
2 parents 3b4e434 + 5a94dc5 commit e84f8d9

File tree

11 files changed

+438
-38
lines changed

11 files changed

+438
-38
lines changed

autowiring/AutoPacket.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,12 @@ class AutoPacket:
512512
return GetSubscribers(typeid(auto_id<T>));
513513
}
514514

515+
/// <returns>All decoration dispositions</returns>
516+
/// <remarks>
517+
/// This method is useful for getting a picture of the entire disposition graph
518+
/// </remarks>
519+
std::list<DecorationDisposition> GetDispositions() const;
520+
515521
/// <returns>All decoration dispositions associated with the data type</returns>
516522
/// <remarks>
517523
/// This method is useful for determining whether flow conditions (broadcast, pipes

autowiring/AutoPacketGraph.h

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
2+
#pragma once
3+
#include "AutoFilterDescriptor.h"
4+
#include "AutoPacket.h"
5+
#include "AutoPacketFactory.h"
6+
#include "Autowired.h"
7+
#include "AutowiringEvents.h"
8+
#include "CoreRunnable.h"
9+
#include STL_UNORDERED_MAP
10+
11+
12+
/// <summary>
13+
/// Represents an edge in the graph from a type to an AutoFilter
14+
/// </summary>
15+
struct DeliveryEdge
16+
{
17+
// The type info
18+
const std::type_info* type_info;
19+
20+
// The AutoFilterDescriptor
21+
AutoFilterDescriptor descriptor;
22+
23+
// Specifies if the argument is an input (type -> descriptor) or output (descriptor -> type)
24+
bool input;
25+
26+
// For the unordered map/hash comparison
27+
bool operator==(const DeliveryEdge& rhs) const {
28+
return
29+
type_info == rhs.type_info &&
30+
descriptor == rhs.descriptor &&
31+
input == rhs.input;
32+
}
33+
};
34+
35+
/// <summary>
36+
/// Using the same hash function as the AutoFilterDescriptor
37+
/// </summary>
38+
namespace std {
39+
template<>
40+
struct hash<DeliveryEdge>
41+
{
42+
size_t operator()(const DeliveryEdge& edge) const {
43+
return (size_t) edge.descriptor.GetAutoFilter()->ptr();
44+
}
45+
};
46+
}
47+
48+
/// <summary>
49+
/// Graphical visualization of AutoPackets
50+
/// </summary>
51+
class AutoPacketGraph:
52+
public AutowiringEvents,
53+
public CoreRunnable
54+
{
55+
public:
56+
AutoPacketGraph();
57+
58+
typedef std::unordered_map<DeliveryEdge, size_t, std::hash<DeliveryEdge>> t_deliveryEdges;
59+
60+
protected:
61+
// A mapping of an edge to the number of times it was delivered
62+
t_deliveryEdges m_deliveryGraph;
63+
64+
// A lock for this type
65+
mutable std::mutex m_lock;
66+
67+
// Reference to the AutoPacketFactory
68+
AutoRequired<AutoPacketFactory> m_factory;
69+
70+
/// <summary>
71+
/// Demangle a type name as well as stripping "auto_in< >"
72+
/// </summary>
73+
/// <remarks>
74+
/// The ">" that encloses the templates will have extra spaces between them, for instance
75+
///
76+
/// auto_in<Class>
77+
/// auto_in<Class<T> >
78+
/// auto_in<Class1<Class2, Class3<Class4> > >
79+
///
80+
/// All we care about is matching "^auto_in<(.*)>$"
81+
/// </remarks>
82+
std::string DemangleTypeName(const std::type_info* type_info) const;
83+
84+
/// <summary>
85+
/// Scan all of the objects and add any AutoFilter's from all of the objects in a system.
86+
/// </summary>
87+
/// <remarks>
88+
/// This function will scan all of the objects (and rescan) and only add new edges to our graph.
89+
/// </remarks>
90+
void LoadEdges();
91+
92+
/// <summary>
93+
/// Record the delivery of a packet and increment the number of times the packet has been delivered
94+
/// </summary>
95+
void RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input);
96+
97+
/// AutowiringEvents overrides
98+
virtual void NewContext(CoreContext&) override {}
99+
virtual void ExpiredContext(CoreContext&) override {}
100+
virtual void EventFired(CoreContext&, const std::type_info&) override {}
101+
virtual void NewObject(CoreContext&, const ObjectTraits&) override;
102+
103+
/// CoreRunnable overrides
104+
virtual bool OnStart(void) override;
105+
106+
public:
107+
/// <summary>
108+
/// Get a copy of the packet via AutoFilter
109+
/// </summary>
110+
void AutoFilter(AutoPacket& packet);
111+
112+
/// <summary>
113+
/// Write the graph to a file in graphviz format
114+
/// </summary>
115+
/// <param name="filename">
116+
/// The name of the file to write the graph to
117+
/// </param>
118+
/// <param name="numPackets">
119+
/// Include the number of times the packet was delivered
120+
/// </param>
121+
bool WriteGV(const std::string& filename, bool numPackets = false) const;
122+
};

autowiring/CoreContext.h

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,25 @@ class CoreContext:
106106
/// </summary>
107107
static std::shared_ptr<CoreContext> GetGlobal(void);
108108

109+
/// <summary>
110+
/// Represents a single entry, together with any deferred elements waiting on the satisfaction of this entry
111+
/// </summary>
112+
struct MemoEntry {
113+
MemoEntry(void) :
114+
pFirst(nullptr)
115+
{}
116+
117+
// The first deferrable autowiring which requires this type, if one exists:
118+
DeferrableAutowiring* pFirst;
119+
120+
// A back reference to the concrete type from which this memo was generated:
121+
const ObjectTraits* pObjTraits;
122+
123+
// Once this memo entry is satisfied, this will contain the AnySharedPointer instance that performs
124+
// the satisfaction
125+
AnySharedPointer m_value;
126+
};
127+
109128
protected:
110129
// A pointer to the parent context
111130
const std::shared_ptr<CoreContext> m_pParent;
@@ -133,22 +152,6 @@ class CoreContext:
133152
typedef std::unordered_map<std::type_index, std::list<BoltBase*>> t_contextNameListeners;
134153
t_contextNameListeners m_nameListeners;
135154

136-
/// <summary>
137-
/// Represents a single entry, together with any deferred elements waiting on the satisfaction of this entry
138-
/// </summary>
139-
struct MemoEntry {
140-
MemoEntry(void) :
141-
pFirst(nullptr)
142-
{}
143-
144-
// The first deferrable autowiring which requires this type, if one exists:
145-
DeferrableAutowiring* pFirst;
146-
147-
// Once this memo entry is satisfied, this will contain the AnySharedPointer instance that performs
148-
// the satisfaction
149-
AnySharedPointer m_value;
150-
};
151-
152155
/// <summary>
153156
/// A proxy context member that knows how to create a factory for a particular type
154157
/// </summary>
@@ -257,7 +260,7 @@ class CoreContext:
257260
/// <summary>
258261
/// Invokes all deferred autowiring fields, generally called after a new member has been added
259262
/// </summary>
260-
void UpdateDeferredElements(std::unique_lock<std::mutex>&& lk, const std::shared_ptr<Object>& entry);
263+
void UpdateDeferredElements(std::unique_lock<std::mutex>&& lk, const ObjectTraits& entry);
261264

262265
/// <summary>
263266
/// Adds the named event receiver to the collection of known receivers
@@ -427,6 +430,19 @@ class CoreContext:
427430
/// </returns>
428431
std::shared_ptr<CoreContext> NextSibling(void) const;
429432

433+
/// <returns>
434+
/// The type identifier of the specified type identifier
435+
/// </returns>
436+
/// <remarks>
437+
/// The returned type structure will be the actual type of the specified object as defined at the time of
438+
/// injection. In the case of a static factory new or AutoFactory new, this type will be the type of the
439+
/// interface. All other members are the concrete type actually injected, as opposed to the type unifier
440+
/// for that type.
441+
///
442+
/// This method will throw an exception if the passed shared pointer is not strictly a member of this context
443+
/// </remarks>
444+
const std::type_info& GetAutoTypeId(const AnySharedPointer& ptr) const;
445+
430446
/// <summary>
431447
/// Creation helper routine
432448
/// </summary>
@@ -505,15 +521,21 @@ class CoreContext:
505521
// Add this type to the TypeRegistry
506522
(void) RegType<T>::r;
507523

508-
// First see if the object has already been injected:
509-
std::shared_ptr<typename CreationRules::TActual> retVal;
510-
FindByType(retVal);
511-
if(retVal)
512-
return std::static_pointer_cast<T>(retVal);
524+
// First see if the base object type has already been injected. This is also necessary to
525+
// ensure that a memo slot is created for the type by itself, in cases where the injected
526+
// member does not inherit Object and this member is eventually satisfied by one that does.
527+
{
528+
std::shared_ptr<T> pure;
529+
FindByType(pure);
530+
if (pure)
531+
return pure;
532+
}
513533

514534
// We must make ourselves current for the remainder of this call:
515535
CurrentContextPusher pshr(shared_from_this());
516-
retVal.reset(CreationRules::New(*this, std::forward<Args>(args)...));
536+
std::shared_ptr<typename CreationRules::TActual> retVal(
537+
CreationRules::New(*this, std::forward<Args>(args)...)
538+
);
517539

518540
// AutoInit if sensible to do so:
519541
CallAutoInit(*retVal, has_autoinit<T>());

autowiring/DecorationDisposition.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct DecorationDisposition
4646
m_type(source.m_type),
4747
m_pImmediate(source.m_pImmediate),
4848
m_publisher(source.m_publisher),
49+
m_subscribers(source.m_subscribers),
4950
isCheckedOut(source.isCheckedOut),
5051
satisfied(source.satisfied)
5152
{}
@@ -54,6 +55,7 @@ struct DecorationDisposition
5455
m_type = source.m_type;
5556
m_pImmediate = source.m_pImmediate;
5657
m_publisher = source.m_publisher;
58+
m_subscribers = source.m_subscribers;
5759
isCheckedOut = source.isCheckedOut;
5860
satisfied = source.satisfied;
5961
return *this;

src/autowiring/AutoPacket.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ AutoPacket::~AutoPacket(void) {
3737
current = current->m_successor.get();
3838
prev_current->m_successor.reset();
3939
}
40+
41+
// Needed for the AutoPacketGraph
42+
NotifyTeardownListeners();
4043
}
4144

4245
DecorationDisposition& AutoPacket::CheckoutImmediateUnsafe(const std::type_info& ti, const void* pvImmed)
@@ -370,6 +373,14 @@ void AutoPacket::RemoveRecipient(Recipient&& recipient) {
370373
m_satCounters.erase(q);
371374
}
372375

376+
std::list<DecorationDisposition> AutoPacket::GetDispositions() const {
377+
std::lock_guard<std::mutex> lk(m_lock);
378+
std::list<DecorationDisposition> dispositions;
379+
for (auto& disposition : m_decorations)
380+
dispositions.push_back(disposition.second);
381+
return dispositions;
382+
}
383+
373384
std::shared_ptr<AutoPacketInternal> AutoPacket::SuccessorInternal(void) {
374385
std::lock_guard<std::mutex> lk(m_lock);
375386

0 commit comments

Comments
 (0)