diff --git a/autowiring/AutoPacket.h b/autowiring/AutoPacket.h index e6097c33c..8e03fb81e 100644 --- a/autowiring/AutoPacket.h +++ b/autowiring/AutoPacket.h @@ -56,6 +56,7 @@ class AutoPacket: // Saturation counters, constructed when the packet is created and reset each time thereafter std::vector m_satCounters; + size_t m_subscriberNum; // The set of decorations currently attached to this object, and the associated lock: mutable std::mutex m_lock; @@ -106,6 +107,11 @@ class AutoPacket: /// void Finalize(void); + /// + /// Adds a recipient for data associated only with this issuance of the packet. + /// + void InitializeRecipient(const AutoFilterDescriptor& descriptor); + /// /// Marks the specified entry as being unsatisfiable /// @@ -405,11 +411,8 @@ class AutoPacket: /// template void AddRecipient(std::function f) { - static_assert(is_auto_filter>::value, "Either arguments or return are not allowed types for AutoFilter methods"); - std::cout << "Decoration overload for std::function called" << std::endl; - //(1) Decide whether the function can be used as an AutoFilter - //(2) Update (with lock) the slot information for this packet only. - //PROBLEM: I need to make sure that the slot does not remain on the packet. + std::shared_ptr> filter(new MicroAutoFilter(f)); + InitializeRecipient(MakeAutoFilterDescriptor(filter)); } /// diff --git a/src/autowiring/AutoPacket.cpp b/src/autowiring/AutoPacket.cpp index 48765c412..e17757a3e 100644 --- a/src/autowiring/AutoPacket.cpp +++ b/src/autowiring/AutoPacket.cpp @@ -55,6 +55,9 @@ AutoPacket::AutoPacket(AutoPacketFactory& factory, const std::shared_ptr } } + // Record divide between subscribers & recipients + m_subscriberNum = m_satCounters.size(); + Reset(); } @@ -213,9 +216,105 @@ void AutoPacket::Finalize(void) { for (SatCounter* call : callQueue) call->CallAutoFilter(*this); + // Remove all recipients & clean up the decorations list + // ASSERT: This reverse the order of accumulation, + // so searching for the subscriber is avoided. + while (m_satCounters.size() > m_subscriberNum) { + SatCounter& recipient = m_satCounters.back(); + + for(auto pCur = recipient.GetAutoFilterInput(); + *pCur; + pCur++ + ) { + DecorationDisposition& entry = m_decorations[*pCur->ti]; + switch(pCur->subscriberType) { + case inTypeInvalid: + // Should never happen--trivially ignore this entry + break; + case inTypeRequired: + assert(entry.m_subscribers.size() > 0); + assert(&recipient == entry.m_subscribers.back().first); + entry.m_subscribers.pop_back(); + break; + case inTypeOptional: + assert(entry.m_subscribers.size() > 0); + assert(&recipient == entry.m_subscribers.back().first); + entry.m_subscribers.pop_back(); + break; + case outTypeRef: + case outTypeRefAutoReady: + assert(&recipient == entry.m_publisher); + entry.m_publisher = nullptr; + break; + } + } + + m_satCounters.pop_back(); + } + + // Remove decoration dispositions specific to subscribers + t_decorationMap::iterator dItr = m_decorations.begin(); + t_decorationMap::iterator dEnd = m_decorations.end(); + while (dItr != dEnd) { + if (dItr->second.m_subscribers.empty()) + dItr = m_decorations.erase(dItr); + else + ++dItr; + } + Reset(); } +void AutoPacket::InitializeRecipient(const AutoFilterDescriptor& descriptor) { + SatCounter* call = nullptr; + { + std::lock_guard lk(m_lock); + + // (1) Append & Initialize new satisfaction counter + m_satCounters.push_back(descriptor); + SatCounter& recipient = m_satCounters.back(); + recipient.Reset(); + + // (2) Update satisfaction & Append types from subscriber + for(auto pCur = recipient.GetAutoFilterInput(); + *pCur; + pCur++ + ) { + DecorationDisposition& entry = m_decorations[*pCur->ti]; + switch(pCur->subscriberType) { + case inTypeInvalid: + // Should never happen--trivially ignore this entry + break; + case inTypeRequired: + entry.m_subscribers.push_back(std::make_pair(&recipient, true)); + if (entry.satisfied) + recipient.Decrement(true); + break; + case inTypeOptional: + entry.m_subscribers.push_back(std::make_pair(&recipient, false)); + if (entry.satisfied) + recipient.Decrement(false); + break; + case outTypeRef: + case outTypeRefAutoReady: + if(entry.m_publisher) + throw autowiring_error("Added two publishers of the same decoration to the same factory"); + entry.m_publisher = &recipient; + break; + } + } + + // (3) Check call status inside of lock + if (recipient) { + call = &recipient; + } + } + + // (3) If all types are satisfied, call AutoFilter now. + if (call) + call->CallAutoFilter(*this); +} + bool AutoPacket::HasSubscribers(const std::type_info& ti) const { std::lock_guard lk(m_lock); return m_decorations.count(ti) != 0; diff --git a/src/autowiring/test/AutoFilterTest.cpp b/src/autowiring/test/AutoFilterTest.cpp index e6eab35e7..d707aa8c8 100644 --- a/src/autowiring/test/AutoFilterTest.cpp +++ b/src/autowiring/test/AutoFilterTest.cpp @@ -1142,6 +1142,7 @@ TEST_F(AutoFilterTest, DISABLED_FunctionDecorationTest) { } //Decoration with function first + //NOTE: This test also catches failures to flush temporary subscriber information { auto packet = factory->NewPacket(); packet->AddRecipient(FilterFunctionType(FilterFunction));