Skip to content

Commit

Permalink
Using MicroAutoFilter to implement Packet::AddRecipient.
Browse files Browse the repository at this point in the history
NOTE: There is a design choice exposed here that might be altered in the future:
Packets are expected to determine their subscribers on construction, rather than initialization.
The consequences of this are:
(1) When a subscriber is added all packet object pools must be flushed.
(2) When a recipient is added it must be removed during the finalize stage.
If instead the subscribers were determined on initialization the ObjectPool flush would be avoided, and the finalize stage could simply be to clear lists.
  • Loading branch information
Gabriel Hare committed Aug 7, 2014
1 parent 803f21e commit b7fb1f1
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 5 deletions.
13 changes: 8 additions & 5 deletions autowiring/AutoPacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class AutoPacket:

// Saturation counters, constructed when the packet is created and reset each time thereafter
std::vector<SatCounter> m_satCounters;
size_t m_subscriberNum;

// The set of decorations currently attached to this object, and the associated lock:
mutable std::mutex m_lock;
Expand Down Expand Up @@ -106,6 +107,11 @@ class AutoPacket:
/// </remarks>
void Finalize(void);

/// <summary>
/// Adds a recipient for data associated only with this issuance of the packet.
/// </summary>
void InitializeRecipient(const AutoFilterDescriptor& descriptor);

/// <summary>
/// Marks the specified entry as being unsatisfiable
/// </summary>
Expand Down Expand Up @@ -405,11 +411,8 @@ class AutoPacket:
/// </summary>
template<class Ret, class... Args>
void AddRecipient(std::function<Ret(Args...)> f) {
static_assert(is_auto_filter<std::function<Ret(Args...)>>::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<MicroAutoFilter<Ret, Args...>> filter(new MicroAutoFilter<Ret, Args...>(f));
InitializeRecipient(MakeAutoFilterDescriptor(filter));
}

/// <returns>
Expand Down
99 changes: 99 additions & 0 deletions src/autowiring/AutoPacket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ AutoPacket::AutoPacket(AutoPacketFactory& factory, const std::shared_ptr<Object>
}
}

// Record divide between subscribers & recipients
m_subscriberNum = m_satCounters.size();

Reset();
}

Expand Down Expand Up @@ -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<std::mutex> 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<std::mutex> lk(m_lock);
return m_decorations.count(ti) != 0;
Expand Down
1 change: 1 addition & 0 deletions src/autowiring/test/AutoFilterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit b7fb1f1

Please sign in to comment.