From f3ba412633a64c998b51534b2b6810b98925bf6b Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 17:13:57 -0800 Subject: [PATCH 01/27] First implementation of the AutoPacketGraph (capable of exporting a .gv file) --- autowiring/AutoPacketGraph.h | 59 +++++++++++ src/autowiring/AutoPacket.cpp | 18 ++++ src/autowiring/AutoPacketGraph.cpp | 53 ++++++++++ src/autowiring/CMakeLists.txt | 2 + src/autowiring/test/AutoPacketGraphTest.cpp | 111 ++++++++++++++++++++ src/autowiring/test/CMakeLists.txt | 1 + 6 files changed, 244 insertions(+) create mode 100644 autowiring/AutoPacketGraph.h create mode 100644 src/autowiring/AutoPacketGraph.cpp create mode 100644 src/autowiring/test/AutoPacketGraphTest.cpp diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h new file mode 100644 index 000000000..3130621f3 --- /dev/null +++ b/autowiring/AutoPacketGraph.h @@ -0,0 +1,59 @@ +// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved. +#pragma once +#include "AutoFilterDescriptor.h" +#include "SatCounter.h" +#include STL_UNORDERED_MAP + + + +/// +/// TODO +/// +struct DeliveryEdge +{ + // The type info + const std::type_info* type_info; + + // + AutoFilterDescriptor descriptor; + + // Specifies if the argument is an + bool input; + + bool operator==(const DeliveryEdge& rhs) const { + // AutoFilter methods are the same for all instances of a class, + // and classes may have more than one AutoFilter method, + // so both comparisons are required. + return + type_info == rhs.type_info && + descriptor == rhs.descriptor && + input == rhs.input; + } +}; + +namespace std { + template<> + struct hash + { + size_t operator()(const DeliveryEdge& edge) const { + return (size_t) edge.descriptor.GetAutoFilter()->ptr(); + } + }; +} + +/// +/// TODO +/// +class AutoPacketGraph +{ +public: + AutoPacketGraph(); + + bool ExportGV(const std::string& filename) const; + + void RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); + +protected: + // A mapping + std::unordered_map> m_deliveryGraph; +}; diff --git a/src/autowiring/AutoPacket.cpp b/src/autowiring/AutoPacket.cpp index d4a1b2312..54c83e8c8 100644 --- a/src/autowiring/AutoPacket.cpp +++ b/src/autowiring/AutoPacket.cpp @@ -3,6 +3,7 @@ #include "AutoPacket.h" #include "Autowired.h" #include "AutoPacketFactory.h" +#include "AutoPacketGraph.h" #include "AutoPacketProfiler.h" #include "AutoFilterDescriptor.h" #include "ContextEnumerator.h" @@ -47,6 +48,23 @@ AutoPacket::~AutoPacket(void) { std::chrono::high_resolution_clock::now() - m_initTime ) ); + + Autowired apg; + if (apg) { + for (auto& itr : m_decorations) { + DecorationDisposition& decoration = itr.second; + + if (decoration.m_publisher) { + apg->RecordDelivery(decoration.m_type, *decoration.m_publisher, false); + } + + for (auto& subscriber : decoration.m_subscribers) { + if (subscriber->called) { + apg->RecordDelivery(decoration.m_type, *subscriber, true); + } + } + } + } } DecorationDisposition& AutoPacket::CheckoutImmediateUnsafe(const std::type_info& ti, const void* pvImmed) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp new file mode 100644 index 000000000..c647216f8 --- /dev/null +++ b/src/autowiring/AutoPacketGraph.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved. +#include "stdafx.h" +#include "AutoPacketGraph.h" +#include "AutoPacketProfiler.h" +#include "demangle.h" +#include + +AutoPacketGraph::AutoPacketGraph() +{ +} + +bool AutoPacketGraph::ExportGV(const std::string& filename) const +{ + std::ofstream file(filename); + if (!file && !file.good()) { + return false; + } + + file << "digraph AutoPacketGraph {\n"; + + for (auto& itr : m_deliveryGraph) { + const DeliveryEdge& edge = itr.first; + // TODO: use counts and labels +// size_t count = itr.second; + + // string format: "type" -> "AutoFilter" (or vice versa) + std::stringstream ss; + ss << " \""; + if (edge.input) { + ss << autowiring::demangle(edge.type_info) << "\" -> \"" << autowiring::demangle(edge.descriptor.GetType()); + } else { + ss << autowiring::demangle(edge.descriptor.GetType()) << "\" -> \"" << autowiring::demangle(edge.type_info); + } + ss << "\"" << std::endl; + + file << ss.str(); + } + + file << "}\n"; + + return true; +} + +void AutoPacketGraph::RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input) { + DeliveryEdge edge { ti, descriptor, input }; + + auto itr = m_deliveryGraph.find(edge); + if (itr == m_deliveryGraph.end()) { + m_deliveryGraph[edge] = 1; + } else { + itr->second++; + } +} diff --git a/src/autowiring/CMakeLists.txt b/src/autowiring/CMakeLists.txt index fc47dab52..bc447c766 100644 --- a/src/autowiring/CMakeLists.txt +++ b/src/autowiring/CMakeLists.txt @@ -32,6 +32,8 @@ set(Autowiring_SRCS AutoPacketInternal.h AutoPacketFactory.cpp AutoPacketFactory.h + AutoPacketGraph.cpp + AutoPacketGraph.h AutoPacketProfiler.cpp AutoPacketProfiler.h AutoParameter.h diff --git a/src/autowiring/test/AutoPacketGraphTest.cpp b/src/autowiring/test/AutoPacketGraphTest.cpp new file mode 100644 index 000000000..29f1a06e7 --- /dev/null +++ b/src/autowiring/test/AutoPacketGraphTest.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved. +#include "stdafx.h" +#include "TestFixtures/Decoration.hpp" +#include +#include +#include CHRONO_HEADER +#include THREAD_HEADER + +class AutoPacketGraphTest: + public testing::Test +{}; + +class APReceiver1 { +public: + APReceiver1(void) {} + + void AutoFilter(Decoration<0> d0) { + m_int0 = d0.i; + } + + int m_int0; +}; + +class APReceiver2 { +public: + APReceiver2(void) {} + + void AutoFilter(Decoration<0> d0, Decoration<1>& d1) { + m_int0 = d0.i; + + d1.i = m_int1; + } + + int m_int0; + int m_int1; +}; + +class APReceiver3 { +public: + APReceiver3(void) {} + + void AutoFilter(Decoration<0> d0, Decoration<1> d1) { + m_int0 = d0.i; + m_int1 = d1.i; + } + + int m_int0; + int m_int1; +}; + +class APReceiver4 { +public: + APReceiver4(void) {} + + void AutoFilter(Decoration<0> d0, Decoration<2> d2) { + m_int0 = d0.i; + m_int2 = d2.i; + } + + int m_int0; + int m_int2; +}; + +TEST_F(AutoPacketGraphTest, SimpleAutoGraph) { + AutoCreateContext ctxt; + CurrentContextPusher pshr(ctxt); + + AutoRequired factory(ctxt); + AutoRequired graph; + + AutoRequired receiver1; + AutoRequired receiver2; + AutoRequired receiver3; + AutoRequired receiver4; + + ctxt->Initiate(); + + int int0 = 12; + int int1 = 34; + int int2 = 56; + + receiver2->m_int1 = int1; + + { + // decorate 1 + auto packet = factory->NewPacket(); + packet->Decorate(Decoration<0>(int0)); + + // TODO: add some real test cases +// ASSERT_EQ(int0, receiver1->m_int0); +// +// ASSERT_EQ(int0, receiver2->m_int0); +// +// ASSERT_EQ(int0, receiver3->m_int0); +// ASSERT_EQ(int1, receiver3->m_int1); + + // decorate 2 + packet->Decorate(Decoration<2>(int2)); + + // TODO: add some real test cases +// ASSERT_EQ(int0, receiver4->m_int0); +// ASSERT_EQ(int2, receiver4->m_int2); + } + + graph->ExportGV("/Users/jnguyen/Desktop/graph.gv"); + + // Shutdown our context, and rundown our factory + ctxt->SignalShutdown(); + factory->Wait(); + +} \ No newline at end of file diff --git a/src/autowiring/test/CMakeLists.txt b/src/autowiring/test/CMakeLists.txt index d355b1f88..a1e1fbd8a 100644 --- a/src/autowiring/test/CMakeLists.txt +++ b/src/autowiring/test/CMakeLists.txt @@ -6,6 +6,7 @@ set(AutowiringTest_SRCS AutoFilterCollapseRulesTest.cpp AutoInjectableTest.cpp AutoPacketFactoryTest.cpp + AutoPacketGraphTest.cpp AutoParameterTest.cpp AutoRestarterTest.cpp AutowiringTest.cpp From 742e81aba9b903ee776fa164f9ac768d8d061fd0 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 17:26:59 -0800 Subject: [PATCH 02/27] protecting the transactions in a lock --- autowiring/AutoPacketGraph.h | 3 +++ src/autowiring/AutoPacketGraph.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 3130621f3..d86dce2ec 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -56,4 +56,7 @@ class AutoPacketGraph protected: // A mapping std::unordered_map> m_deliveryGraph; + + // A lock for this type + mutable std::mutex m_lock; }; diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index c647216f8..83aabfadd 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -18,6 +18,7 @@ bool AutoPacketGraph::ExportGV(const std::string& filename) const file << "digraph AutoPacketGraph {\n"; + std::lock_guard lk(m_lock); for (auto& itr : m_deliveryGraph) { const DeliveryEdge& edge = itr.first; // TODO: use counts and labels @@ -44,6 +45,7 @@ bool AutoPacketGraph::ExportGV(const std::string& filename) const void AutoPacketGraph::RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input) { DeliveryEdge edge { ti, descriptor, input }; + std::lock_guard lk(m_lock); auto itr = m_deliveryGraph.find(edge); if (itr == m_deliveryGraph.end()) { m_deliveryGraph[edge] = 1; From 4836c598979ab8337b142569ee54d9623c23fdcb Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 17:30:12 -0800 Subject: [PATCH 03/27] =?UTF-8?q?Adding=20the=20packet=20=E2=80=9Ccount?= =?UTF-8?q?=E2=80=9D=20to=20the=20graph?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/autowiring/AutoPacketGraph.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 83aabfadd..ff9f1d1ef 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -21,8 +21,7 @@ bool AutoPacketGraph::ExportGV(const std::string& filename) const std::lock_guard lk(m_lock); for (auto& itr : m_deliveryGraph) { const DeliveryEdge& edge = itr.first; - // TODO: use counts and labels -// size_t count = itr.second; + size_t count = itr.second; // string format: "type" -> "AutoFilter" (or vice versa) std::stringstream ss; @@ -32,7 +31,9 @@ bool AutoPacketGraph::ExportGV(const std::string& filename) const } else { ss << autowiring::demangle(edge.descriptor.GetType()) << "\" -> \"" << autowiring::demangle(edge.type_info); } - ss << "\"" << std::endl; + + // TODO: count should probably be optional + ss << "\" [label=\"" << count << "\"];" << std::endl; file << ss.str(); } From 47a0ddc3e963f0b93b550113b566ce684355486a Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 17:36:08 -0800 Subject: [PATCH 04/27] Renaming the function API names and adding some comments --- autowiring/AutoPacketGraph.h | 10 ++++++-- src/autowiring/AutoPacket.cpp | 4 +-- src/autowiring/AutoPacketGraph.cpp | 27 +++++++++++---------- src/autowiring/test/AutoPacketGraphTest.cpp | 2 +- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index d86dce2ec..59d21fee4 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -49,9 +49,15 @@ class AutoPacketGraph public: AutoPacketGraph(); - bool ExportGV(const std::string& filename) const; + /// + /// Add an edge to the graph given the following parameters + /// + void AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); - void RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); + /// + /// Write the graph to a file in graphviz format + /// + bool WriteGV(const std::string& filename) const; protected: // A mapping diff --git a/src/autowiring/AutoPacket.cpp b/src/autowiring/AutoPacket.cpp index 54c83e8c8..7c84608a8 100644 --- a/src/autowiring/AutoPacket.cpp +++ b/src/autowiring/AutoPacket.cpp @@ -55,12 +55,12 @@ AutoPacket::~AutoPacket(void) { DecorationDisposition& decoration = itr.second; if (decoration.m_publisher) { - apg->RecordDelivery(decoration.m_type, *decoration.m_publisher, false); + apg->AddEdge(decoration.m_type, *decoration.m_publisher, false); } for (auto& subscriber : decoration.m_subscribers) { if (subscriber->called) { - apg->RecordDelivery(decoration.m_type, *subscriber, true); + apg->AddEdge(decoration.m_type, *subscriber, true); } } } diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index ff9f1d1ef..ed7989777 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -9,7 +9,20 @@ AutoPacketGraph::AutoPacketGraph() { } -bool AutoPacketGraph::ExportGV(const std::string& filename) const + +void AutoPacketGraph::AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input) { + DeliveryEdge edge { ti, descriptor, input }; + + std::lock_guard lk(m_lock); + auto itr = m_deliveryGraph.find(edge); + if (itr == m_deliveryGraph.end()) { + m_deliveryGraph[edge] = 1; + } else { + itr->second++; + } +} + +bool AutoPacketGraph::WriteGV(const std::string& filename) const { std::ofstream file(filename); if (!file && !file.good()) { @@ -42,15 +55,3 @@ bool AutoPacketGraph::ExportGV(const std::string& filename) const return true; } - -void AutoPacketGraph::RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input) { - DeliveryEdge edge { ti, descriptor, input }; - - std::lock_guard lk(m_lock); - auto itr = m_deliveryGraph.find(edge); - if (itr == m_deliveryGraph.end()) { - m_deliveryGraph[edge] = 1; - } else { - itr->second++; - } -} diff --git a/src/autowiring/test/AutoPacketGraphTest.cpp b/src/autowiring/test/AutoPacketGraphTest.cpp index 29f1a06e7..bb9dfb19f 100644 --- a/src/autowiring/test/AutoPacketGraphTest.cpp +++ b/src/autowiring/test/AutoPacketGraphTest.cpp @@ -102,7 +102,7 @@ TEST_F(AutoPacketGraphTest, SimpleAutoGraph) { // ASSERT_EQ(int2, receiver4->m_int2); } - graph->ExportGV("/Users/jnguyen/Desktop/graph.gv"); + graph->WriteGV("/Users/jnguyen/Desktop/graph.gv"); // Shutdown our context, and rundown our factory ctxt->SignalShutdown(); From 51423fc7a65eefe2f389b25acbe3e347f15a45f3 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 18:35:26 -0800 Subject: [PATCH 05/27] Refactoring the AutoPacketGraph to use AutoFilter with the AutoPacket& backdoor. This required adding a AutoPacket::GetDispositions() function and copying the subscribers list to the DecorationDisposition copy constructor --- autowiring/AutoPacket.h | 6 ++++++ autowiring/AutoPacketGraph.h | 5 ++++- autowiring/DecorationDisposition.h | 2 ++ src/autowiring/AutoPacket.cpp | 27 ++++++++++----------------- src/autowiring/AutoPacketGraph.cpp | 16 ++++++++++++++++ 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/autowiring/AutoPacket.h b/autowiring/AutoPacket.h index ed11e6690..00b05fd2f 100644 --- a/autowiring/AutoPacket.h +++ b/autowiring/AutoPacket.h @@ -465,6 +465,12 @@ class AutoPacket: /// All subscribers to the specified data std::list GetSubscribers(const std::type_info& data) const; + /// All decoration dispositions + /// + /// This method is useful for getting a picture of the entire disposition graph + /// + std::list GetDispositions() const; + /// All decoration dispositions associated with the data type /// /// This method is useful for determining whether flow conditions (broadcast, pipes diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 59d21fee4..5ac596a8b 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -1,11 +1,12 @@ // Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved. #pragma once #include "AutoFilterDescriptor.h" +#include "AutoPacket.h" +#include "DecorationDisposition.h" #include "SatCounter.h" #include STL_UNORDERED_MAP - /// /// TODO /// @@ -54,6 +55,8 @@ class AutoPacketGraph /// void AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); + void AutoFilter(AutoPacket& packet); + /// /// Write the graph to a file in graphviz format /// diff --git a/autowiring/DecorationDisposition.h b/autowiring/DecorationDisposition.h index 0eb2c3c37..7c10d45a3 100644 --- a/autowiring/DecorationDisposition.h +++ b/autowiring/DecorationDisposition.h @@ -46,6 +46,7 @@ struct DecorationDisposition m_type(source.m_type), m_pImmediate(source.m_pImmediate), m_publisher(source.m_publisher), + m_subscribers(source.m_subscribers), isCheckedOut(source.isCheckedOut), satisfied(source.satisfied) {} @@ -54,6 +55,7 @@ struct DecorationDisposition m_type = source.m_type; m_pImmediate = source.m_pImmediate; m_publisher = source.m_publisher; + m_subscribers = source.m_subscribers; isCheckedOut = source.isCheckedOut; satisfied = source.satisfied; return *this; diff --git a/src/autowiring/AutoPacket.cpp b/src/autowiring/AutoPacket.cpp index 7c84608a8..f8ad93866 100644 --- a/src/autowiring/AutoPacket.cpp +++ b/src/autowiring/AutoPacket.cpp @@ -3,7 +3,6 @@ #include "AutoPacket.h" #include "Autowired.h" #include "AutoPacketFactory.h" -#include "AutoPacketGraph.h" #include "AutoPacketProfiler.h" #include "AutoFilterDescriptor.h" #include "ContextEnumerator.h" @@ -49,22 +48,8 @@ AutoPacket::~AutoPacket(void) { ) ); - Autowired apg; - if (apg) { - for (auto& itr : m_decorations) { - DecorationDisposition& decoration = itr.second; - - if (decoration.m_publisher) { - apg->AddEdge(decoration.m_type, *decoration.m_publisher, false); - } - - for (auto& subscriber : decoration.m_subscribers) { - if (subscriber->called) { - apg->AddEdge(decoration.m_type, *subscriber, true); - } - } - } - } + // Needed for the AutoPacketGraph + NotifyTeardownListeners(); } DecorationDisposition& AutoPacket::CheckoutImmediateUnsafe(const std::type_info& ti, const void* pvImmed) @@ -375,6 +360,14 @@ std::list AutoPacket::GetSubscribers(const std::type_info& data) con return subscribers; } +std::list AutoPacket::GetDispositions() const { + std::lock_guard lk(m_lock); + std::list dispositions; + for (auto& disposition : m_decorations) + dispositions.push_back(disposition.second); + return dispositions; +} + std::list AutoPacket::GetDispositions(const std::type_info& data) const { std::lock_guard lk(m_lock); std::list dispositions; diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index ed7989777..71a00fa85 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -22,6 +22,22 @@ void AutoPacketGraph::AddEdge(const std::type_info* ti, const AutoFilterDescript } } +void AutoPacketGraph::AutoFilter(AutoPacket& packet) { + packet.AddTeardownListener([this, &packet] () { + for (auto& decoration : packet.GetDispositions()) { + if (decoration.m_publisher) { + AddEdge(decoration.m_type, *decoration.m_publisher, false); + } + + for (auto& subscriber : decoration.m_subscribers) { + if (subscriber->called) { + AddEdge(decoration.m_type, *subscriber, true); + } + } + } + }); +} + bool AutoPacketGraph::WriteGV(const std::string& filename) const { std::ofstream file(filename); From 5a05517de1f51d07b42d85deeab1aaa0b087b36e Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 18:57:28 -0800 Subject: [PATCH 06/27] Drawing the shapes for graphviz (types are rectangles, AutoFilters are ellipses) --- src/autowiring/AutoPacketGraph.cpp | 32 ++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 71a00fa85..9e2f807c0 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -48,17 +48,33 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const file << "digraph AutoPacketGraph {\n"; std::lock_guard lk(m_lock); + + // Containers for the unique types and descriptors + std::unordered_set types; + std::unordered_set> descriptors; + + // draw the edges for (auto& itr : m_deliveryGraph) { - const DeliveryEdge& edge = itr.first; - size_t count = itr.second; + auto& edge = itr.first; + auto type = edge.type_info; + auto& descriptor = edge.descriptor; + auto count = itr.second; + + if (types.find(type) == types.end()) { + types.insert(type); + } + + if (descriptors.find(descriptor) == descriptors.end()) { + descriptors.insert(descriptor); + } // string format: "type" -> "AutoFilter" (or vice versa) std::stringstream ss; ss << " \""; if (edge.input) { - ss << autowiring::demangle(edge.type_info) << "\" -> \"" << autowiring::demangle(edge.descriptor.GetType()); + ss << autowiring::demangle(type) << "\" -> \"" << autowiring::demangle(descriptor.GetType()); } else { - ss << autowiring::demangle(edge.descriptor.GetType()) << "\" -> \"" << autowiring::demangle(edge.type_info); + ss << autowiring::demangle(descriptor.GetType()) << "\" -> \"" << autowiring::demangle(type); } // TODO: count should probably be optional @@ -66,6 +82,14 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const file << ss.str(); } + file << std::endl; + + // Setup the shapes for the types and descriptors + for (auto& type : types) + file << " \"" << autowiring::demangle(type) << "\" [shape=box];" << std::endl; + + for (auto& descriptor : descriptors) + file << " \"" << autowiring::demangle(descriptor.GetType()) << "\" [shape=ellipse];" << std::endl; file << "}\n"; From b2e5bb2febb857afdd3c139aad1d9dec4ba66f53 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 19:38:40 -0800 Subject: [PATCH 07/27] Adding some comments --- autowiring/AutoPacketGraph.h | 20 ++++++++++++-------- src/autowiring/AutoPacketGraph.cpp | 10 +++++----- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 5ac596a8b..8b5085752 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -8,23 +8,21 @@ /// -/// TODO +/// Represents an edge in the graph from a type to an AutoFilter /// struct DeliveryEdge { // The type info const std::type_info* type_info; - // + // The AutoFilterDescriptor AutoFilterDescriptor descriptor; - // Specifies if the argument is an + // Specifies if the argument is an input (type -> descriptor) or output (descriptor -> type) bool input; + // For the unordered map/hash comparison bool operator==(const DeliveryEdge& rhs) const { - // AutoFilter methods are the same for all instances of a class, - // and classes may have more than one AutoFilter method, - // so both comparisons are required. return type_info == rhs.type_info && descriptor == rhs.descriptor && @@ -32,6 +30,9 @@ struct DeliveryEdge } }; +/// +/// Using the same hash function as the AutoFilterDescriptor +/// namespace std { template<> struct hash @@ -43,7 +44,7 @@ namespace std { } /// -/// TODO +/// Graphical visualization of AutoPackets /// class AutoPacketGraph { @@ -55,6 +56,9 @@ class AutoPacketGraph /// void AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); + /// + /// Get a copy of the packet via AutoFilter + /// void AutoFilter(AutoPacket& packet); /// @@ -63,7 +67,7 @@ class AutoPacketGraph bool WriteGV(const std::string& filename) const; protected: - // A mapping + // A mapping of an edge to the number of times it was delivered std::unordered_map> m_deliveryGraph; // A lock for this type diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 9e2f807c0..fc46b4551 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -53,20 +53,20 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const std::unordered_set types; std::unordered_set> descriptors; - // draw the edges for (auto& itr : m_deliveryGraph) { auto& edge = itr.first; auto type = edge.type_info; auto& descriptor = edge.descriptor; auto count = itr.second; - if (types.find(type) == types.end()) { + // TODO: skip if type == AutoPacketGraph + + // Get a unique set of types/descriptors + if (types.find(type) == types.end()) types.insert(type); - } - if (descriptors.find(descriptor) == descriptors.end()) { + if (descriptors.find(descriptor) == descriptors.end()) descriptors.insert(descriptor); - } // string format: "type" -> "AutoFilter" (or vice versa) std::stringstream ss; From ad6e6bbf3257850027eecdd664465ac7275127bd Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 19:42:35 -0800 Subject: [PATCH 08/27] Slight optimization to store the string names instead to avoid repeated demangling --- src/autowiring/AutoPacketGraph.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index fc46b4551..7563cf728 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -4,6 +4,7 @@ #include "AutoPacketProfiler.h" #include "demangle.h" #include +#include AutoPacketGraph::AutoPacketGraph() { @@ -50,8 +51,8 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const std::lock_guard lk(m_lock); // Containers for the unique types and descriptors - std::unordered_set types; - std::unordered_set> descriptors; + std::unordered_set typeNames; + std::unordered_set descriptorNames; for (auto& itr : m_deliveryGraph) { auto& edge = itr.first; @@ -61,20 +62,23 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const // TODO: skip if type == AutoPacketGraph + std::string typeName = autowiring::demangle(type); + std::string descriptorName = autowiring::demangle(descriptor.GetType()); + // Get a unique set of types/descriptors - if (types.find(type) == types.end()) - types.insert(type); + if (typeNames.find(typeName) == typeNames.end()) + typeNames.insert(typeName); - if (descriptors.find(descriptor) == descriptors.end()) - descriptors.insert(descriptor); + if (descriptorNames.find(descriptorName) == descriptorNames.end()) + descriptorNames.insert(descriptorName); // string format: "type" -> "AutoFilter" (or vice versa) std::stringstream ss; ss << " \""; if (edge.input) { - ss << autowiring::demangle(type) << "\" -> \"" << autowiring::demangle(descriptor.GetType()); + ss << typeName << "\" -> \"" << descriptorName; } else { - ss << autowiring::demangle(descriptor.GetType()) << "\" -> \"" << autowiring::demangle(type); + ss << descriptorName << "\" -> \"" << typeName; } // TODO: count should probably be optional @@ -85,11 +89,11 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const file << std::endl; // Setup the shapes for the types and descriptors - for (auto& type : types) - file << " \"" << autowiring::demangle(type) << "\" [shape=box];" << std::endl; + for (auto& typeName : typeNames) + file << " \"" << typeName << "\" [shape=box];" << std::endl; - for (auto& descriptor : descriptors) - file << " \"" << autowiring::demangle(descriptor.GetType()) << "\" [shape=ellipse];" << std::endl; + for (auto& descriptorName : descriptorNames) + file << " \"" << descriptorName << "\" [shape=ellipse];" << std::endl; file << "}\n"; From eb1cedd49198ff6b1d88955665198f407d285ce5 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 16 Dec 2014 20:00:07 -0800 Subject: [PATCH 09/27] Titling the graph with the context name --- src/autowiring/AutoPacketGraph.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 7563cf728..7c8c4f18f 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -2,6 +2,7 @@ #include "stdafx.h" #include "AutoPacketGraph.h" #include "AutoPacketProfiler.h" +#include "CoreContext.h" #include "demangle.h" #include #include @@ -46,7 +47,7 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const return false; } - file << "digraph AutoPacketGraph {\n"; + file << "digraph \"" << autowiring::demangle(CoreContext::CurrentContext()->GetSigilType()) << " context\" {\n"; std::lock_guard lk(m_lock); From facf477bb7c6f86109bbc8e2cd0be7da983a5cfa Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Wed, 17 Dec 2014 10:31:15 -0800 Subject: [PATCH 10/27] Fixed small bug where publisher needs to check if it has been called --- src/autowiring/AutoPacketGraph.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 7c8c4f18f..504df0b48 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -27,13 +27,16 @@ void AutoPacketGraph::AddEdge(const std::type_info* ti, const AutoFilterDescript void AutoPacketGraph::AutoFilter(AutoPacket& packet) { packet.AddTeardownListener([this, &packet] () { for (auto& decoration : packet.GetDispositions()) { - if (decoration.m_publisher) { - AddEdge(decoration.m_type, *decoration.m_publisher, false); + auto publisher = decoration.m_publisher; + auto type = decoration.m_type; + + if (publisher && publisher->called) { + AddEdge(type, *publisher, false); } for (auto& subscriber : decoration.m_subscribers) { if (subscriber->called) { - AddEdge(decoration.m_type, *subscriber, true); + AddEdge(type, *subscriber, true); } } } From f934d34770b17109007a51a4738061fb9d048d99 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Wed, 17 Dec 2014 10:31:56 -0800 Subject: [PATCH 11/27] Moving includes to cpp --- autowiring/AutoPacketGraph.h | 2 -- src/autowiring/AutoPacketGraph.cpp | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 8b5085752..a9e155594 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -2,8 +2,6 @@ #pragma once #include "AutoFilterDescriptor.h" #include "AutoPacket.h" -#include "DecorationDisposition.h" -#include "SatCounter.h" #include STL_UNORDERED_MAP diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 504df0b48..25699cb6b 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -3,7 +3,9 @@ #include "AutoPacketGraph.h" #include "AutoPacketProfiler.h" #include "CoreContext.h" +#include "DecorationDisposition.h" #include "demangle.h" +#include "SatCounter.h" #include #include From cba9b3a5af5745ccfcb8f58d85beb9ad44f6a5c2 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Wed, 17 Dec 2014 10:40:13 -0800 Subject: [PATCH 12/27] minor style cleanup --- autowiring/AutoPacketGraph.h | 16 +++++++++------- src/autowiring/AutoPacketGraph.cpp | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index a9e155594..1dc6d97c3 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -49,11 +49,20 @@ class AutoPacketGraph public: AutoPacketGraph(); +protected: + // A mapping of an edge to the number of times it was delivered + typedef std::unordered_map> t_deliveryGraph; + t_deliveryGraph m_deliveryGraph; + + // A lock for this type + mutable std::mutex m_lock; + /// /// Add an edge to the graph given the following parameters /// void AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); +public: /// /// Get a copy of the packet via AutoFilter /// @@ -63,11 +72,4 @@ class AutoPacketGraph /// Write the graph to a file in graphviz format /// bool WriteGV(const std::string& filename) const; - -protected: - // A mapping of an edge to the number of times it was delivered - std::unordered_map> m_deliveryGraph; - - // A lock for this type - mutable std::mutex m_lock; }; diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 25699cb6b..36c03187e 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -9,11 +9,11 @@ #include #include + AutoPacketGraph::AutoPacketGraph() { } - void AutoPacketGraph::AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input) { DeliveryEdge edge { ti, descriptor, input }; @@ -52,7 +52,7 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const return false; } - file << "digraph \"" << autowiring::demangle(CoreContext::CurrentContext()->GetSigilType()) << " context\" {\n"; + file << "digraph \"" << autowiring::demangle(CoreContext::CurrentContext()->GetSigilType()) << " context\" {" << std::endl; std::lock_guard lk(m_lock); From 0a054468df3f10063081311fa3be688f13438413 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Thu, 18 Dec 2014 11:41:46 -0800 Subject: [PATCH 13/27] Renaming the delivery edge map and adding a getter to return a copy of the edge map --- autowiring/AutoPacketGraph.h | 9 +++++++-- src/autowiring/AutoPacketGraph.cpp | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 1dc6d97c3..bde921985 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -51,8 +51,8 @@ class AutoPacketGraph protected: // A mapping of an edge to the number of times it was delivered - typedef std::unordered_map> t_deliveryGraph; - t_deliveryGraph m_deliveryGraph; + typedef std::unordered_map> t_deliveryEdges; + t_deliveryEdges m_deliveryGraph; // A lock for this type mutable std::mutex m_lock; @@ -68,6 +68,11 @@ class AutoPacketGraph /// void AutoFilter(AutoPacket& packet); + /// + /// Get a mapping of the DeliveryEdge to the number of times the AutoFilter was called + /// + t_deliveryEdges GetEdgeCounts() const; + /// /// Write the graph to a file in graphviz format /// diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 36c03187e..258061464 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -45,6 +45,10 @@ void AutoPacketGraph::AutoFilter(AutoPacket& packet) { }); } +AutoPacketGraph::t_deliveryEdges AutoPacketGraph::GetEdgeCounts() const { + return m_deliveryGraph; +} + bool AutoPacketGraph::WriteGV(const std::string& filename) const { std::ofstream file(filename); From 28b95b0d8c8467822b7921b6ec8ec12314696da5 Mon Sep 17 00:00:00 2001 From: Jason Lokerson Date: Wed, 17 Dec 2014 10:56:08 -0800 Subject: [PATCH 14/27] Adding a true type reconciliation function This allows a user to pass an AnySharedPointer to a CoreContext, and retrieve an std::type_info corresponding to the unaliased concrete type that is known to that context. This provides diagnostics utilities to elide the TypeUnifierSimple and TypeUnifierComplex wrapper types in cases where those types are injected. --- autowiring/CoreContext.h | 68 ++++++++++++------- src/autowiring/CoreContext.cpp | 32 ++++++--- .../test/AutoFilterDiagnosticsTest.cpp | 38 +++++++++++ src/autowiring/test/CMakeLists.txt | 1 + src/autowiring/test/CoreContextTest.cpp | 2 +- 5 files changed, 109 insertions(+), 32 deletions(-) create mode 100644 src/autowiring/test/AutoFilterDiagnosticsTest.cpp diff --git a/autowiring/CoreContext.h b/autowiring/CoreContext.h index 0797f3167..f9073b237 100644 --- a/autowiring/CoreContext.h +++ b/autowiring/CoreContext.h @@ -106,6 +106,25 @@ class CoreContext: /// static std::shared_ptr GetGlobal(void); + /// + /// Represents a single entry, together with any deferred elements waiting on the satisfaction of this entry + /// + struct MemoEntry { + MemoEntry(void) : + pFirst(nullptr) + {} + + // The first deferrable autowiring which requires this type, if one exists: + DeferrableAutowiring* pFirst; + + // A back reference to the concrete type from which this memo was generated: + const ObjectTraits* pObjTraits; + + // Once this memo entry is satisfied, this will contain the AnySharedPointer instance that performs + // the satisfaction + AnySharedPointer m_value; + }; + protected: // A pointer to the parent context const std::shared_ptr m_pParent; @@ -130,22 +149,6 @@ class CoreContext: typedef std::unordered_map> t_contextNameListeners; t_contextNameListeners m_nameListeners; - /// - /// Represents a single entry, together with any deferred elements waiting on the satisfaction of this entry - /// - struct MemoEntry { - MemoEntry(void) : - pFirst(nullptr) - {} - - // The first deferrable autowiring which requires this type, if one exists: - DeferrableAutowiring* pFirst; - - // Once this memo entry is satisfied, this will contain the AnySharedPointer instance that performs - // the satisfaction - AnySharedPointer m_value; - }; - /// /// A proxy context member that knows how to create a factory for a particular type /// @@ -254,7 +257,7 @@ class CoreContext: /// /// Invokes all deferred autowiring fields, generally called after a new member has been added /// - void UpdateDeferredElements(std::unique_lock&& lk, const std::shared_ptr& entry); + void UpdateDeferredElements(std::unique_lock&& lk, const ObjectTraits& entry); /// /// Adds the named event receiver to the collection of known receivers @@ -412,6 +415,19 @@ class CoreContext: /// std::shared_ptr NextSibling(void) const; + /// + /// The type identifier of the specified type identifier + /// + /// + /// The returned type structure will be the actual type of the specified object as defined at the time of + /// injection. In the case of a static factory new or AutoFactory new, this type will be the type of the + /// interface. All other members are the concrete type actually injected, as opposed to the type unifier + /// for that type. + /// + /// This method will throw an exception if the passed shared pointer is not strictly a member of this context + /// + const std::type_info& GetAutoTypeId(const AnySharedPointer& ptr) const; + /// /// Creation helper routine /// @@ -490,15 +506,21 @@ class CoreContext: // Add this type to the TypeRegistry (void) RegType::r; - // First see if the object has already been injected: - std::shared_ptr retVal; - FindByType(retVal); - if(retVal) - return std::static_pointer_cast(retVal); + // First see if the base object type has already been injected. This is also necessary to + // ensure that a memo slot is created for the type by itself, in cases where the injected + // member does not inherit Object and this member is eventually satisfied by one that does. + { + std::shared_ptr pure; + FindByType(pure); + if (pure) + return pure; + } // We must make ourselves current for the remainder of this call: CurrentContextPusher pshr(shared_from_this()); - retVal.reset(CreationRules::New(*this, std::forward(args)...)); + std::shared_ptr retVal( + CreationRules::New(*this, std::forward(args)...) + ); // AutoInit if sensible to do so: CallAutoInit(*retVal, has_autoinit()); diff --git a/src/autowiring/CoreContext.cpp b/src/autowiring/CoreContext.cpp index 173b0140c..8b1cf31f5 100644 --- a/src/autowiring/CoreContext.cpp +++ b/src/autowiring/CoreContext.cpp @@ -156,6 +156,18 @@ std::shared_ptr CoreContext::NextSibling(void) const { return std::shared_ptr(); } +const std::type_info& CoreContext::GetAutoTypeId(const AnySharedPointer& ptr) const { + std::lock_guard lk(m_stateBlock->m_lock); + + const std::type_info& ti = ptr->type(); + auto q = m_typeMemos.find(ti); + if (q == m_typeMemos.end() || !q->second.pObjTraits) + throw autowiring_error("Attempted to obtain the true type of a shared pointer that was not a member of this context"); + + const ObjectTraits* pObjTraits = q->second.pObjTraits; + return pObjTraits->type; +} + std::shared_ptr CoreContext::IncrementOutstandingThreadCount(void) { std::shared_ptr retVal = m_outstanding.lock(); if(retVal) @@ -224,7 +236,7 @@ void CoreContext::AddInternal(const ObjectTraits& traits) { // Notify any autowiring field that is currently waiting that we have a new member // to be considered. - UpdateDeferredElements(std::move(lk), traits.pObject); + UpdateDeferredElements(std::move(lk), m_concreteTypes.back()); } // Event receivers: @@ -274,23 +286,24 @@ CoreContext::MemoEntry& CoreContext::FindByTypeUnsafe(AnySharedPointer& referenc } // Resolve based on iterated dynamic casts for each concrete type: - bool assigned = false; + const ObjectTraits* pObjTraits = nullptr; for(const auto& type : m_concreteTypes) { if(!reference->try_assign(*type.value)) // No match, try the next entry continue; - if(assigned) + if (pObjTraits) // Resolution ambiguity, cannot proceed throw autowiring_error("An attempt was made to resolve a type which has multiple possible clients"); - // Update the found-flag: - assigned = true; + // Update the object traits reference: + pObjTraits = &type; } // This entry was not formerly memoized. Memoize unconditionally. MemoEntry& retVal = m_typeMemos[type]; retVal.m_value = reference; + retVal.pObjTraits = pObjTraits; return retVal; } @@ -601,7 +614,7 @@ void CoreContext::BroadcastContextCreationNotice(const std::type_info& sigil) co m_pParent->BroadcastContextCreationNotice(sigil); } -void CoreContext::UpdateDeferredElements(std::unique_lock&& lk, const std::shared_ptr& entry) { +void CoreContext::UpdateDeferredElements(std::unique_lock&& lk, const ObjectTraits& entry) { // Collection of satisfiable lists: std::vector> satisfiable; @@ -620,7 +633,7 @@ void CoreContext::UpdateDeferredElements(std::unique_lock&& lk, cons // Each connected nonroot deferrable autowiring is referred to as a "dependant chain". std::stack stk; for(auto& cur : m_typeMemos) { - auto& value = cur.second; + MemoEntry& value = cur.second; if(value.m_value) // This entry is already satisfied, no need to process it @@ -629,9 +642,12 @@ void CoreContext::UpdateDeferredElements(std::unique_lock&& lk, cons // Determine whether the current candidate element satisfies the autowiring we are considering. // This is done internally via a dynamic cast on the interface type for which this polymorphic // base type was constructed. - if(!value.m_value->try_assign(entry)) + if(!value.m_value->try_assign(entry.pObject)) continue; + // Success, assign the traits + value.pObjTraits = &entry; + // Now we need to take on the responsibility of satisfying this deferral. We will do this by // nullifying the flink, and by ensuring that the memo is satisfied at the point where we // release the lock. diff --git a/src/autowiring/test/AutoFilterDiagnosticsTest.cpp b/src/autowiring/test/AutoFilterDiagnosticsTest.cpp new file mode 100644 index 000000000..58e2d35f6 --- /dev/null +++ b/src/autowiring/test/AutoFilterDiagnosticsTest.cpp @@ -0,0 +1,38 @@ +#include "stdafx.h" +#include +#include + +class AutoFilterDiagnosticsTest: + public testing::Test +{ +public: + AutoFilterDiagnosticsTest(void) { + AutoCurrentContext()->Initiate(); + } +}; + +class FilterMemberNotInheritingObject { +public: + void AutoFilter(const int&) {} +}; + +TEST_F(AutoFilterDiagnosticsTest, CanGetExpectedTrueType) { + AutoRequired mnio; + AutoRequired factory; + + auto packet = factory->NewPacket(); + auto dispositions = packet->GetDispositions(); + ASSERT_EQ(1UL, dispositions.size()) << "Dispositions collection contained an unexpected AutoFilter"; + + auto& disposition = dispositions.front(); + ASSERT_EQ(1UL, disposition.m_subscribers.size()) << "Expected exactly one subscriber for the sole present type"; + + const SatCounter* descriptor = disposition.m_subscribers.front(); + AnySharedPointer asp(descriptor->GetAutoFilter()); + + // Get more information about this object from the enclosing context: + AutoCurrentContext ctxt; + const std::type_info* ti; + ASSERT_NO_THROW(ti = &ctxt->GetAutoTypeId(asp)) << "Exception thrown while attempting to get true type information"; + ASSERT_EQ(typeid(FilterMemberNotInheritingObject), *ti) << "True type not correctly reported, got " << autowiring::demangle(*ti) << ", expected FilterMemberNotInheritingObject"; +} \ No newline at end of file diff --git a/src/autowiring/test/CMakeLists.txt b/src/autowiring/test/CMakeLists.txt index c631d990e..91e8e9071 100644 --- a/src/autowiring/test/CMakeLists.txt +++ b/src/autowiring/test/CMakeLists.txt @@ -4,6 +4,7 @@ set(AutowiringTest_SRCS AutoConfigTest.cpp AutoConstructTest.cpp AutoFilterCollapseRulesTest.cpp + AutoFilterDiagnosticsTest.cpp AutoInjectableTest.cpp AutoPacketFactoryTest.cpp AutoPacketGraphTest.cpp diff --git a/src/autowiring/test/CoreContextTest.cpp b/src/autowiring/test/CoreContextTest.cpp index 3e61a8dbb..63dc2cce7 100644 --- a/src/autowiring/test/CoreContextTest.cpp +++ b/src/autowiring/test/CoreContextTest.cpp @@ -214,4 +214,4 @@ TEST_F(CoreContextTest, NoEnumerateBeforeBoltReturn) { // Need to block until this thread is done t.join(); -} \ No newline at end of file +} From cfed8d0d9634465728de8dd3cc45966997bf889f Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Thu, 18 Dec 2014 16:01:58 -0800 Subject: [PATCH 15/27] =?UTF-8?q?Made=20AutoPacketFactory=20an=20member=20?= =?UTF-8?q?variable=20and=20implementing=20Jason=E2=80=99s=20true=20type?= =?UTF-8?q?=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autowiring/AutoPacketGraph.h | 5 +++++ src/autowiring/AutoPacketGraph.cpp | 8 +++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index bde921985..0f8a24893 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -2,6 +2,8 @@ #pragma once #include "AutoFilterDescriptor.h" #include "AutoPacket.h" +#include "AutoPacketFactory.h" +#include "Autowired.h" #include STL_UNORDERED_MAP @@ -57,6 +59,9 @@ class AutoPacketGraph // A lock for this type mutable std::mutex m_lock; + // Reference to the AutoPacketFactory + Autowired m_factory; + /// /// Add an edge to the graph given the following parameters /// diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 258061464..593f3abb2 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -1,7 +1,6 @@ // Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved. #include "stdafx.h" #include "AutoPacketGraph.h" -#include "AutoPacketProfiler.h" #include "CoreContext.h" #include "DecorationDisposition.h" #include "demangle.h" @@ -70,10 +69,13 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const auto& descriptor = edge.descriptor; auto count = itr.second; - // TODO: skip if type == AutoPacketGraph + const std::type_info& descType = m_factory->GetContext()->GetAutoTypeId(descriptor.GetAutoFilter()); + if (descType == typeid(AutoPacketGraph)) { + continue; + } std::string typeName = autowiring::demangle(type); - std::string descriptorName = autowiring::demangle(descriptor.GetType()); + std::string descriptorName = autowiring::demangle(descType); // Get a unique set of types/descriptors if (typeNames.find(typeName) == typeNames.end()) From 3c59ee63e99022c7416e5507082e05800f712b0a Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Thu, 18 Dec 2014 17:09:39 -0800 Subject: [PATCH 16/27] Simplifying the test receiver signatures --- src/autowiring/test/AutoPacketGraphTest.cpp | 29 +++++---------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/src/autowiring/test/AutoPacketGraphTest.cpp b/src/autowiring/test/AutoPacketGraphTest.cpp index bb9dfb19f..41804de02 100644 --- a/src/autowiring/test/AutoPacketGraphTest.cpp +++ b/src/autowiring/test/AutoPacketGraphTest.cpp @@ -13,44 +13,27 @@ class AutoPacketGraphTest: class APReceiver1 { public: APReceiver1(void) {} - - void AutoFilter(Decoration<0> d0) { - m_int0 = d0.i; - } - - int m_int0; + void AutoFilter(Decoration<0> d0) { } }; class APReceiver2 { public: APReceiver2(void) {} - - void AutoFilter(Decoration<0> d0, Decoration<1>& d1) { - m_int0 = d0.i; - - d1.i = m_int1; - } - - int m_int0; - int m_int1; + void AutoFilter(Decoration<0> d0, Decoration<1>& d1) { } }; class APReceiver3 { public: APReceiver3(void) {} - - void AutoFilter(Decoration<0> d0, Decoration<1> d1) { - m_int0 = d0.i; - m_int1 = d1.i; - } - - int m_int0; - int m_int1; + void AutoFilter(Decoration<0> d0, Decoration<1> d1) { } }; class APReceiver4 { public: APReceiver4(void) {} + void AutoFilter(Decoration<0> d0, Decoration<2> d2) { } +}; + void AutoFilter(Decoration<0> d0, Decoration<2> d2) { m_int0 = d0.i; From 46a1d9bf0e5001d24666483e9cdee8eaf2fe463a Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Thu, 18 Dec 2014 17:12:03 -0800 Subject: [PATCH 17/27] Slight refactor to CoreContext::Initiate() to only hold the lock for the thread list at the time of lock acquisition --- src/autowiring/CoreContext.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/autowiring/CoreContext.cpp b/src/autowiring/CoreContext.cpp index 8b1cf31f5..d4b112474 100644 --- a/src/autowiring/CoreContext.cpp +++ b/src/autowiring/CoreContext.cpp @@ -371,13 +371,20 @@ void CoreContext::Initiate(void) { // Reacquire the lock to prevent m_threads from being modified while we sit on it auto outstanding = IncrementOutstandingThreadCount(); - std::lock_guard lk(m_stateBlock->m_lock); - - // Signal our condition variable - m_stateBlock->m_stateChanged.notify_all(); + + // Get the end of the thread list that we have at the time of lock acquisition + t_threadList::iterator end; + + { + std::lock_guard lk(m_stateBlock->m_lock); + end = m_threads.end(); + + // Signal our condition variable + m_stateBlock->m_stateChanged.notify_all(); + } - for(CoreRunnable* q : m_threads) - q->Start(outstanding); + for (auto q = m_threads.begin(); q != end; ++q) + (*q)->Start(outstanding); } void CoreContext::InitiateCoreThreads(void) { From 8d210ed58ac9f5fcbb23c804fbac3bb3d2785205 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Fri, 19 Dec 2014 12:56:51 -0800 Subject: [PATCH 18/27] Making AutoPacketGraph inherit from AutowiringEvents so that it can rescan for edges on AutowiringEvents::NewObject and CoreRunnable so that it can load the system when the context has been initiated. Added more test cases (and stubs/todos) --- autowiring/AutoPacketGraph.h | 32 +++++- src/autowiring/AutoPacketGraph.cpp | 68 ++++++++++--- src/autowiring/test/AutoPacketGraphTest.cpp | 107 ++++++++++++-------- 3 files changed, 149 insertions(+), 58 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 0f8a24893..8686653f9 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -4,6 +4,8 @@ #include "AutoPacket.h" #include "AutoPacketFactory.h" #include "Autowired.h" +#include "AutowiringEvents.h" +#include "CoreRunnable.h" #include STL_UNORDERED_MAP @@ -46,26 +48,46 @@ namespace std { /// /// Graphical visualization of AutoPackets /// -class AutoPacketGraph +class AutoPacketGraph: + public AutowiringEvents, + public CoreRunnable { public: AutoPacketGraph(); + typedef std::unordered_map> t_deliveryEdges; + protected: // A mapping of an edge to the number of times it was delivered - typedef std::unordered_map> t_deliveryEdges; t_deliveryEdges m_deliveryGraph; // A lock for this type mutable std::mutex m_lock; // Reference to the AutoPacketFactory - Autowired m_factory; + AutoRequired m_factory; + + /// + /// Scan all of the objects and add any AutoFilter's from all of the objects in a system. + /// + /// + /// This function will scan all of the objects (and rescan) and only add new edges to our graph. + /// + void LoadEdges(); /// - /// Add an edge to the graph given the following parameters + /// Record the delivery of a packet and increment the number of times the packet has been delivered /// - void AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); + void RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); + + /// AutowiringEvents overrides + virtual void NewContext(CoreContext&) {} + virtual void ExpiredContext(CoreContext&) {} + virtual void EventFired(CoreContext&, const std::type_info&) {} + virtual void NewObject(CoreContext&, const ObjectTraits&); + + /// CoreRunnable overrides + virtual bool DoStart(void); public: /// diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 593f3abb2..39eaae146 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -7,22 +7,64 @@ #include "SatCounter.h" #include #include +#include FUNCTIONAL_HEADER +AutoPacketGraph::AutoPacketGraph() { +} -AutoPacketGraph::AutoPacketGraph() -{ +void AutoPacketGraph::LoadEdges() { + std::lock_guard lk(m_lock); + + std::list descriptors; + m_factory->AppendAutoFiltersTo(descriptors); + + // Sort, eliminate duplicates + descriptors.sort(); + descriptors.erase(std::unique(descriptors.begin(), descriptors.end()), descriptors.end()); + + for (auto& descriptor : descriptors) { + for(auto pCur = descriptor.GetAutoFilterInput(); *pCur; pCur++) { + const std::type_info& type_info = *pCur->ti; + + // Skip the AutoPacketGraph + const std::type_info& descType = m_factory->GetContext()->GetAutoTypeId(descriptor.GetAutoFilter()); + if (descType == typeid(AutoPacketGraph)) { + continue; + } + + if (pCur->is_input) { + DeliveryEdge edge { &type_info, descriptor, true }; + if (m_deliveryGraph.find(edge) == m_deliveryGraph.end()) { + m_deliveryGraph[edge] = 0; + } + } + + if (pCur->is_output) { + DeliveryEdge edge { &type_info, descriptor, false }; + if (m_deliveryGraph.find(edge) == m_deliveryGraph.end()) { + m_deliveryGraph[edge] = 0; + } + } + } + } } -void AutoPacketGraph::AddEdge(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input) { +void AutoPacketGraph::RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input) { DeliveryEdge edge { ti, descriptor, input }; - std::lock_guard lk(m_lock); auto itr = m_deliveryGraph.find(edge); - if (itr == m_deliveryGraph.end()) { - m_deliveryGraph[edge] = 1; - } else { - itr->second++; - } + assert(itr != m_deliveryGraph.end()); + itr->second++; +} + +void AutoPacketGraph::NewObject(CoreContext&, const ObjectTraits&) { + LoadEdges(); +} + +bool AutoPacketGraph::DoStart(void) { + LoadEdges(); + + return false; } void AutoPacketGraph::AutoFilter(AutoPacket& packet) { @@ -32,12 +74,12 @@ void AutoPacketGraph::AutoFilter(AutoPacket& packet) { auto type = decoration.m_type; if (publisher && publisher->called) { - AddEdge(type, *publisher, false); + RecordDelivery(type, *publisher, false); } for (auto& subscriber : decoration.m_subscribers) { if (subscriber->called) { - AddEdge(type, *subscriber, true); + RecordDelivery(type, *subscriber, true); } } } @@ -48,8 +90,7 @@ AutoPacketGraph::t_deliveryEdges AutoPacketGraph::GetEdgeCounts() const { return m_deliveryGraph; } -bool AutoPacketGraph::WriteGV(const std::string& filename) const -{ +bool AutoPacketGraph::WriteGV(const std::string& filename) const { std::ofstream file(filename); if (!file && !file.good()) { return false; @@ -69,6 +110,7 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const auto& descriptor = edge.descriptor; auto count = itr.second; + // Skip the AutoPacketGraph const std::type_info& descType = m_factory->GetContext()->GetAutoTypeId(descriptor.GetAutoFilter()); if (descType == typeid(AutoPacketGraph)) { continue; diff --git a/src/autowiring/test/AutoPacketGraphTest.cpp b/src/autowiring/test/AutoPacketGraphTest.cpp index 41804de02..62b94a7d4 100644 --- a/src/autowiring/test/AutoPacketGraphTest.cpp +++ b/src/autowiring/test/AutoPacketGraphTest.cpp @@ -34,61 +34,88 @@ class APReceiver4 { void AutoFilter(Decoration<0> d0, Decoration<2> d2) { } }; + +TEST_F(AutoPacketGraphTest, VerifyEmptyGraphBeforeCtxtInit) { + AutoCreateContext ctxt; + CurrentContextPusher pshr(ctxt); - void AutoFilter(Decoration<0> d0, Decoration<2> d2) { - m_int0 = d0.i; - m_int2 = d2.i; - } + AutoRequired graph; + ASSERT_TRUE(graph->GetEdgeCounts().empty()) + << "Graph did not start out empty before context initiation"; - int m_int0; - int m_int2; -}; + ctxt->Initiate(); + + ASSERT_TRUE(graph->GetEdgeCounts().empty()) + << "Graph did not stay empty after context initiation"; + + ctxt->SignalShutdown(); +} -TEST_F(AutoPacketGraphTest, SimpleAutoGraph) { +TEST_F(AutoPacketGraphTest, VerifyEmptyGraphAfterCtxtInit) { AutoCreateContext ctxt; CurrentContextPusher pshr(ctxt); - AutoRequired factory(ctxt); + ctxt->Initiate(); + AutoRequired graph; + ASSERT_TRUE(graph->GetEdgeCounts().empty()) + << "Graph did not start out empty"; + ctxt->SignalShutdown(); +} + +TEST_F(AutoPacketGraphTest, VerifySimpleEdgeFromObjectBeforeInit) { + AutoCreateContext ctxt; + CurrentContextPusher pshr(ctxt); + + AutoRequired graph; AutoRequired receiver1; - AutoRequired receiver2; - AutoRequired receiver3; - AutoRequired receiver4; - ctxt->Initiate(); + ASSERT_TRUE(graph->GetEdgeCounts().empty()) + << "Graph should still be empty before context is initialized"; - int int0 = 12; - int int1 = 34; - int int2 = 56; + ctxt->Initiate(); - receiver2->m_int1 = int1; + ASSERT_EQ(1UL, graph->GetEdgeCounts().size()) + << "Graph did not detect AutoFilter from object after being initiated"; - { - // decorate 1 - auto packet = factory->NewPacket(); - packet->Decorate(Decoration<0>(int0)); + ctxt->SignalShutdown(); +} - // TODO: add some real test cases -// ASSERT_EQ(int0, receiver1->m_int0); -// -// ASSERT_EQ(int0, receiver2->m_int0); -// -// ASSERT_EQ(int0, receiver3->m_int0); -// ASSERT_EQ(int1, receiver3->m_int1); - - // decorate 2 - packet->Decorate(Decoration<2>(int2)); +TEST_F(AutoPacketGraphTest, VerifySimpleInputFilter) { + // TODO +} - // TODO: add some real test cases -// ASSERT_EQ(int0, receiver4->m_int0); -// ASSERT_EQ(int2, receiver4->m_int2); - } +TEST_F(AutoPacketGraphTest, VerifySimpleOutputFilter) { + // TODO +} + +TEST_F(AutoPacketGraphTest, VerifyPacketDecorationIncrementingCount) { + // TODO +} + +TEST_F(AutoPacketGraphTest, VerifyLoadAutoFilterSystem) { + AutoCreateContext ctxt; + CurrentContextPusher pshr(ctxt); - graph->WriteGV("/Users/jnguyen/Desktop/graph.gv"); + AutoRequired factory(ctxt); + AutoRequired graph; - // Shutdown our context, and rundown our factory - ctxt->SignalShutdown(); - factory->Wait(); + ctxt->Initiate(); + + AutoRequired receiver1; + AutoRequired receiver2; + AutoRequired receiver3; + AutoRequired receiver4; + + AutoPacketGraph::t_deliveryEdges edges = graph->GetEdgeCounts(); + + ASSERT_EQ(7UL, edges.size()) + << "Graph could not load the edges from new objects"; -} \ No newline at end of file + for (auto& itr : edges) { + ASSERT_EQ(0UL, itr.second) + << "Coutn should be 0 since packets have not been delivered yet"; + } +} + From 42637f743b3d885db89ed688a8d9cd373bb198eb Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Fri, 19 Dec 2014 13:54:36 -0800 Subject: [PATCH 19/27] Fixing issue where finding the iterator to the beginning of the list instead of the front since we push to the front of m_threads --- src/autowiring/CoreContext.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/autowiring/CoreContext.cpp b/src/autowiring/CoreContext.cpp index d4b112474..71557bb3b 100644 --- a/src/autowiring/CoreContext.cpp +++ b/src/autowiring/CoreContext.cpp @@ -372,18 +372,18 @@ void CoreContext::Initiate(void) { // Reacquire the lock to prevent m_threads from being modified while we sit on it auto outstanding = IncrementOutstandingThreadCount(); - // Get the end of the thread list that we have at the time of lock acquisition - t_threadList::iterator end; + // Get the beginning of the thread list that we have at the time of lock acquisition + t_threadList::iterator beginning; { std::lock_guard lk(m_stateBlock->m_lock); - end = m_threads.end(); + beginning = m_threads.begin(); // Signal our condition variable m_stateBlock->m_stateChanged.notify_all(); } - for (auto q = m_threads.begin(); q != end; ++q) + for (auto q = beginning; q != m_threads.end(); ++q) (*q)->Start(outstanding); } From 854fb59b43ceab02740c9d06926ce3356ec7886a Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Fri, 19 Dec 2014 14:14:30 -0800 Subject: [PATCH 20/27] Updating the override methods from the CoreRunnable refactor --- autowiring/AutoPacketGraph.h | 10 +++++----- src/autowiring/AutoPacketGraph.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 8686653f9..e7b2c5444 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -81,13 +81,13 @@ class AutoPacketGraph: void RecordDelivery(const std::type_info* ti, const AutoFilterDescriptor& descriptor, bool input); /// AutowiringEvents overrides - virtual void NewContext(CoreContext&) {} - virtual void ExpiredContext(CoreContext&) {} - virtual void EventFired(CoreContext&, const std::type_info&) {} - virtual void NewObject(CoreContext&, const ObjectTraits&); + virtual void NewContext(CoreContext&) override {} + virtual void ExpiredContext(CoreContext&) override {} + virtual void EventFired(CoreContext&, const std::type_info&) override {} + virtual void NewObject(CoreContext&, const ObjectTraits&) override; /// CoreRunnable overrides - virtual bool DoStart(void); + virtual bool OnStart(void) override; public: /// diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 39eaae146..cf30d1c5c 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -61,7 +61,7 @@ void AutoPacketGraph::NewObject(CoreContext&, const ObjectTraits&) { LoadEdges(); } -bool AutoPacketGraph::DoStart(void) { +bool AutoPacketGraph::OnStart(void) { LoadEdges(); return false; From 2de9b58cb649e19368ddc7757c83632abcc37276 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Mon, 22 Dec 2014 16:36:17 -0800 Subject: [PATCH 21/27] =?UTF-8?q?Stripping=20the=20=E2=80=9Cauto=5Fin<=20>?= =?UTF-8?q?=E2=80=9D=20from=20the=20demangled=20type=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autowiring/AutoPacketGraph.h | 14 ++++++++++++++ src/autowiring/AutoPacketGraph.cpp | 14 +++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index e7b2c5444..ed4fae3a0 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -67,6 +67,20 @@ class AutoPacketGraph: // Reference to the AutoPacketFactory AutoRequired m_factory; + /// + /// Demangle a type name as well as stripping "auto_in< >" + /// + /// + /// The ">" that encloses the templates will have extra spaces between them, for instance + /// + /// auto_in + /// auto_in > + /// auto_in > > + /// + /// All we care about is matching "^auto_in<(.*)>$" + /// + std::string DemangleTypeName(const std::type_info* type_info) const; + /// /// Scan all of the objects and add any AutoFilter's from all of the objects in a system. /// diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index cf30d1c5c..b8132d837 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -12,6 +12,18 @@ AutoPacketGraph::AutoPacketGraph() { } +std::string AutoPacketGraph::DemangleTypeName(const std::type_info* type_info) const { + std::string demangled = autowiring::demangle(type_info); + + size_t demangledLength = demangled.length(); + size_t newLength = + demangled[demangledLength - 2] == ' ' ? + demangledLength - 10 : + demangledLength - 9; + + return demangled.substr(demangled.find("<") + 1, newLength); +} + void AutoPacketGraph::LoadEdges() { std::lock_guard lk(m_lock); @@ -116,7 +128,7 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const { continue; } - std::string typeName = autowiring::demangle(type); + std::string typeName = DemangleTypeName(type); std::string descriptorName = autowiring::demangle(descType); // Get a unique set of types/descriptors From f9a12da9475a640235a9fc817c8d215fd517acba Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Mon, 22 Dec 2014 16:45:47 -0800 Subject: [PATCH 22/27] Adding an optional parameter to add the number of times a packet was delivered --- autowiring/AutoPacketGraph.h | 8 +++++++- src/autowiring/AutoPacketGraph.cpp | 12 +++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index ed4fae3a0..1edbdd02b 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -117,5 +117,11 @@ class AutoPacketGraph: /// /// Write the graph to a file in graphviz format /// - bool WriteGV(const std::string& filename) const; + /// + /// The name of the file to write the graph to + /// + /// + /// Include the number of times the packet was delivered + /// + bool WriteGV(const std::string& filename, bool numPackets = false) const; }; diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index b8132d837..9aa43183b 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -102,7 +102,7 @@ AutoPacketGraph::t_deliveryEdges AutoPacketGraph::GetEdgeCounts() const { return m_deliveryGraph; } -bool AutoPacketGraph::WriteGV(const std::string& filename) const { +bool AutoPacketGraph::WriteGV(const std::string& filename, bool numPackets) const { std::ofstream file(filename); if (!file && !file.good()) { return false; @@ -142,13 +142,15 @@ bool AutoPacketGraph::WriteGV(const std::string& filename) const { std::stringstream ss; ss << " \""; if (edge.input) { - ss << typeName << "\" -> \"" << descriptorName; + ss << typeName << "\" -> \"" << descriptorName << "\""; } else { - ss << descriptorName << "\" -> \"" << typeName; + ss << descriptorName << "\" -> \"" << typeName << "\""; } - // TODO: count should probably be optional - ss << "\" [label=\"" << count << "\"];" << std::endl; + if (numPackets) + ss << "[label=\"" << count << "\"];"; + + ss << std::endl; file << ss.str(); } From ac79d4e87f292885699b0f5f1eb0879bcf35a392 Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Mon, 22 Dec 2014 17:53:38 -0800 Subject: [PATCH 23/27] More tests --- src/autowiring/AutoPacketGraph.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index 9aa43183b..cec5111e8 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -90,6 +90,12 @@ void AutoPacketGraph::AutoFilter(AutoPacket& packet) { } for (auto& subscriber : decoration.m_subscribers) { + // Skip the AutoPacketGraph + const std::type_info& descType = m_factory->GetContext()->GetAutoTypeId(subscriber->GetAutoFilter()); + if (descType == typeid(AutoPacketGraph)) { + continue; + } + if (subscriber->called) { RecordDelivery(type, *subscriber, true); } From a7d451915a42f89fb76e9999624aaa696f97098b Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 23 Dec 2014 00:25:13 -0800 Subject: [PATCH 24/27] adding 2 quick tests --- src/autowiring/test/AutoPacketGraphTest.cpp | 43 +++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/autowiring/test/AutoPacketGraphTest.cpp b/src/autowiring/test/AutoPacketGraphTest.cpp index 62b94a7d4..dfb43a7ee 100644 --- a/src/autowiring/test/AutoPacketGraphTest.cpp +++ b/src/autowiring/test/AutoPacketGraphTest.cpp @@ -82,6 +82,41 @@ TEST_F(AutoPacketGraphTest, VerifySimpleEdgeFromObjectBeforeInit) { ctxt->SignalShutdown(); } +TEST_F(AutoPacketGraphTest, VerifySimpleEdgeFromNewObject) { + AutoCreateContext ctxt; + CurrentContextPusher pshr(ctxt); + + AutoRequired graph; + + ctxt->Initiate(); + + ASSERT_TRUE(graph->GetEdgeCounts().empty()) + << "Graph should still be empty before context is initialized"; + + AutoRequired receiver1; + + ASSERT_EQ(1UL, graph->GetEdgeCounts().size()) + << "Graph did not detect AutoFilter from object after being initiated"; + + ctxt->SignalShutdown(); +} + +TEST_F(AutoPacketGraphTest, VerifyLoadGraphAfterInitAndObject) { + AutoCreateContext ctxt; + CurrentContextPusher pshr(ctxt); + + AutoRequired receiver1; + + ctxt->Initiate(); + + AutoRequired graph; + + ASSERT_EQ(1UL, graph->GetEdgeCounts().size()) + << "Graph did not detect AutoFilter from object after being initiated"; + + ctxt->SignalShutdown(); +} + TEST_F(AutoPacketGraphTest, VerifySimpleInputFilter) { // TODO } @@ -110,6 +145,12 @@ TEST_F(AutoPacketGraphTest, VerifyLoadAutoFilterSystem) { AutoPacketGraph::t_deliveryEdges edges = graph->GetEdgeCounts(); + { + auto packet = factory->NewPacket(); + packet->Decorate(Decoration<0>(0)); + packet->Decorate(Decoration<2>(2)); + } + ASSERT_EQ(7UL, edges.size()) << "Graph could not load the edges from new objects"; @@ -117,5 +158,7 @@ TEST_F(AutoPacketGraphTest, VerifyLoadAutoFilterSystem) { ASSERT_EQ(0UL, itr.second) << "Coutn should be 0 since packets have not been delivered yet"; } + + ctxt->SignalShutdown(); } From fff21daefbaeeb1fe43564f9283e0506effa71de Mon Sep 17 00:00:00 2001 From: Jimmy Nguyen Date: Tue, 23 Dec 2014 00:27:08 -0800 Subject: [PATCH 25/27] Removing the GetEdges() API until the feature is more defined. As a result, removing the unit tests as well. --- autowiring/AutoPacketGraph.h | 5 - src/autowiring/AutoPacketGraph.cpp | 4 - src/autowiring/test/AutoPacketGraphTest.cpp | 164 -------------------- src/autowiring/test/CMakeLists.txt | 1 - 4 files changed, 174 deletions(-) delete mode 100644 src/autowiring/test/AutoPacketGraphTest.cpp diff --git a/autowiring/AutoPacketGraph.h b/autowiring/AutoPacketGraph.h index 1edbdd02b..cc29f67ce 100644 --- a/autowiring/AutoPacketGraph.h +++ b/autowiring/AutoPacketGraph.h @@ -109,11 +109,6 @@ class AutoPacketGraph: /// void AutoFilter(AutoPacket& packet); - /// - /// Get a mapping of the DeliveryEdge to the number of times the AutoFilter was called - /// - t_deliveryEdges GetEdgeCounts() const; - /// /// Write the graph to a file in graphviz format /// diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index cec5111e8..b3820eea9 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -104,10 +104,6 @@ void AutoPacketGraph::AutoFilter(AutoPacket& packet) { }); } -AutoPacketGraph::t_deliveryEdges AutoPacketGraph::GetEdgeCounts() const { - return m_deliveryGraph; -} - bool AutoPacketGraph::WriteGV(const std::string& filename, bool numPackets) const { std::ofstream file(filename); if (!file && !file.good()) { diff --git a/src/autowiring/test/AutoPacketGraphTest.cpp b/src/autowiring/test/AutoPacketGraphTest.cpp deleted file mode 100644 index dfb43a7ee..000000000 --- a/src/autowiring/test/AutoPacketGraphTest.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved. -#include "stdafx.h" -#include "TestFixtures/Decoration.hpp" -#include -#include -#include CHRONO_HEADER -#include THREAD_HEADER - -class AutoPacketGraphTest: - public testing::Test -{}; - -class APReceiver1 { -public: - APReceiver1(void) {} - void AutoFilter(Decoration<0> d0) { } -}; - -class APReceiver2 { -public: - APReceiver2(void) {} - void AutoFilter(Decoration<0> d0, Decoration<1>& d1) { } -}; - -class APReceiver3 { -public: - APReceiver3(void) {} - void AutoFilter(Decoration<0> d0, Decoration<1> d1) { } -}; - -class APReceiver4 { -public: - APReceiver4(void) {} - void AutoFilter(Decoration<0> d0, Decoration<2> d2) { } -}; - - -TEST_F(AutoPacketGraphTest, VerifyEmptyGraphBeforeCtxtInit) { - AutoCreateContext ctxt; - CurrentContextPusher pshr(ctxt); - - AutoRequired graph; - ASSERT_TRUE(graph->GetEdgeCounts().empty()) - << "Graph did not start out empty before context initiation"; - - ctxt->Initiate(); - - ASSERT_TRUE(graph->GetEdgeCounts().empty()) - << "Graph did not stay empty after context initiation"; - - ctxt->SignalShutdown(); -} - -TEST_F(AutoPacketGraphTest, VerifyEmptyGraphAfterCtxtInit) { - AutoCreateContext ctxt; - CurrentContextPusher pshr(ctxt); - - ctxt->Initiate(); - - AutoRequired graph; - ASSERT_TRUE(graph->GetEdgeCounts().empty()) - << "Graph did not start out empty"; - - ctxt->SignalShutdown(); -} - -TEST_F(AutoPacketGraphTest, VerifySimpleEdgeFromObjectBeforeInit) { - AutoCreateContext ctxt; - CurrentContextPusher pshr(ctxt); - - AutoRequired graph; - AutoRequired receiver1; - - ASSERT_TRUE(graph->GetEdgeCounts().empty()) - << "Graph should still be empty before context is initialized"; - - ctxt->Initiate(); - - ASSERT_EQ(1UL, graph->GetEdgeCounts().size()) - << "Graph did not detect AutoFilter from object after being initiated"; - - ctxt->SignalShutdown(); -} - -TEST_F(AutoPacketGraphTest, VerifySimpleEdgeFromNewObject) { - AutoCreateContext ctxt; - CurrentContextPusher pshr(ctxt); - - AutoRequired graph; - - ctxt->Initiate(); - - ASSERT_TRUE(graph->GetEdgeCounts().empty()) - << "Graph should still be empty before context is initialized"; - - AutoRequired receiver1; - - ASSERT_EQ(1UL, graph->GetEdgeCounts().size()) - << "Graph did not detect AutoFilter from object after being initiated"; - - ctxt->SignalShutdown(); -} - -TEST_F(AutoPacketGraphTest, VerifyLoadGraphAfterInitAndObject) { - AutoCreateContext ctxt; - CurrentContextPusher pshr(ctxt); - - AutoRequired receiver1; - - ctxt->Initiate(); - - AutoRequired graph; - - ASSERT_EQ(1UL, graph->GetEdgeCounts().size()) - << "Graph did not detect AutoFilter from object after being initiated"; - - ctxt->SignalShutdown(); -} - -TEST_F(AutoPacketGraphTest, VerifySimpleInputFilter) { - // TODO -} - -TEST_F(AutoPacketGraphTest, VerifySimpleOutputFilter) { - // TODO -} - -TEST_F(AutoPacketGraphTest, VerifyPacketDecorationIncrementingCount) { - // TODO -} - -TEST_F(AutoPacketGraphTest, VerifyLoadAutoFilterSystem) { - AutoCreateContext ctxt; - CurrentContextPusher pshr(ctxt); - - AutoRequired factory(ctxt); - AutoRequired graph; - - ctxt->Initiate(); - - AutoRequired receiver1; - AutoRequired receiver2; - AutoRequired receiver3; - AutoRequired receiver4; - - AutoPacketGraph::t_deliveryEdges edges = graph->GetEdgeCounts(); - - { - auto packet = factory->NewPacket(); - packet->Decorate(Decoration<0>(0)); - packet->Decorate(Decoration<2>(2)); - } - - ASSERT_EQ(7UL, edges.size()) - << "Graph could not load the edges from new objects"; - - for (auto& itr : edges) { - ASSERT_EQ(0UL, itr.second) - << "Coutn should be 0 since packets have not been delivered yet"; - } - - ctxt->SignalShutdown(); -} - diff --git a/src/autowiring/test/CMakeLists.txt b/src/autowiring/test/CMakeLists.txt index 91e8e9071..d7223e1eb 100644 --- a/src/autowiring/test/CMakeLists.txt +++ b/src/autowiring/test/CMakeLists.txt @@ -7,7 +7,6 @@ set(AutowiringTest_SRCS AutoFilterDiagnosticsTest.cpp AutoInjectableTest.cpp AutoPacketFactoryTest.cpp - AutoPacketGraphTest.cpp AutoParameterTest.cpp AutoRestarterTest.cpp AutowiringTest.cpp From e10f2959b19cd0cc43e441c4e16edb5a7e129113 Mon Sep 17 00:00:00 2001 From: Jason Lokerson Date: Tue, 23 Dec 2014 07:02:58 -0800 Subject: [PATCH 26/27] Added missing copyright notice --- src/autowiring/test/AutoFilterDiagnosticsTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/autowiring/test/AutoFilterDiagnosticsTest.cpp b/src/autowiring/test/AutoFilterDiagnosticsTest.cpp index 58e2d35f6..e4e190656 100644 --- a/src/autowiring/test/AutoFilterDiagnosticsTest.cpp +++ b/src/autowiring/test/AutoFilterDiagnosticsTest.cpp @@ -1,3 +1,4 @@ +// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved. #include "stdafx.h" #include #include From 5a94dc54667cc6b397a324357286639b100a2820 Mon Sep 17 00:00:00 2001 From: Jason Lokerson Date: Tue, 23 Dec 2014 07:08:57 -0800 Subject: [PATCH 27/27] Added missing header file reference --- src/autowiring/AutoPacketGraph.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/autowiring/AutoPacketGraph.cpp b/src/autowiring/AutoPacketGraph.cpp index b3820eea9..e92ed348e 100644 --- a/src/autowiring/AutoPacketGraph.cpp +++ b/src/autowiring/AutoPacketGraph.cpp @@ -5,6 +5,7 @@ #include "DecorationDisposition.h" #include "demangle.h" #include "SatCounter.h" +#include #include #include #include FUNCTIONAL_HEADER