565 lines
16 KiB
C++
565 lines
16 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2007 INRIA
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation;
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
|
*/
|
|
#include "composite-trace-resolver.h"
|
|
#include "debug.h"
|
|
|
|
NS_DEBUG_COMPONENT_DEFINE ("CompositeTraceResolver");
|
|
|
|
namespace ns3 {
|
|
|
|
CompositeTraceResolver::CompositeTraceResolver ()
|
|
{}
|
|
|
|
CompositeTraceResolver::~CompositeTraceResolver ()
|
|
{
|
|
for (TraceItems::iterator i = m_items.begin (); i != m_items.end (); i++)
|
|
{
|
|
delete *i;
|
|
}
|
|
m_items.clear ();
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::AddItem (CompositeItem *item)
|
|
{
|
|
m_items.push_back (item);
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::Add (std::string name,
|
|
Callback<Ptr<TraceResolver> > createResolver)
|
|
{
|
|
class MakerCompositeItem : public CompositeItem
|
|
{
|
|
public:
|
|
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
|
|
{maker ()->Connect (subpath, cb, context);}
|
|
virtual void Disconnect (std::string subpath, const CallbackBase &cb)
|
|
{maker ()->Disconnect (subpath, cb);}
|
|
virtual void CollectSources (std::string path, const TraceContext &context,
|
|
SourceCollection *collection)
|
|
{
|
|
path.append ("/");
|
|
path.append (this->name);
|
|
TraceContext ctx = context;
|
|
ctx.Union (this->context);
|
|
this->maker ()->CollectSources (path, ctx, collection);
|
|
}
|
|
Callback<Ptr<TraceResolver> > maker;
|
|
} *item = new MakerCompositeItem ();
|
|
item->name = name;
|
|
item->context = TraceContext ();
|
|
item->maker = createResolver;
|
|
AddItem (item);
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::AddSource (std::string name,
|
|
const TraceDoc &doc,
|
|
const TraceSource &trace)
|
|
{
|
|
DoAddSource (name, doc, trace, TraceContext ());
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::DoAddSource (std::string name,
|
|
const TraceDoc &doc,
|
|
const TraceSource &trace,
|
|
const TraceContext &context)
|
|
{
|
|
class SourceCompositeItem : public CompositeItem
|
|
{
|
|
public:
|
|
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
|
|
{if (subpath == "") {trace->AddCallback (cb, context);}}
|
|
virtual void Disconnect (std::string subpath, const CallbackBase &cb)
|
|
{if (subpath == "") {trace->RemoveCallback (cb);}}
|
|
virtual void CollectSources (std::string path, const TraceContext &context,
|
|
SourceCollection *collection)
|
|
{
|
|
path.append ("/");
|
|
path.append (this->name);
|
|
TraceContext ctx = context;
|
|
ctx.Union (this->context);
|
|
collection->AddUnique (path, ctx, this->doc);
|
|
}
|
|
TraceSource *trace;
|
|
TraceDoc doc;
|
|
} *item = new SourceCompositeItem ();
|
|
item->name = name;
|
|
item->context = context;
|
|
item->trace = const_cast<TraceSource *> (&trace);
|
|
item->doc = doc;
|
|
AddItem (item);
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
CompositeTraceResolver::AddChild (std::string name, Ptr<Object> child)
|
|
{
|
|
DoAddChild (name, child, TraceContext ());
|
|
}
|
|
void
|
|
CompositeTraceResolver::DoAddChild (std::string name, Ptr<Object> child, const TraceContext &context)
|
|
{
|
|
class ChildCompositeItem : public CompositeItem
|
|
{
|
|
public:
|
|
virtual void Connect (std::string subpath, const CallbackBase &cb, const TraceContext &context)
|
|
{child->GetTraceResolver ()->Connect (subpath, cb, context);}
|
|
virtual void Disconnect (std::string subpath, const CallbackBase &cb)
|
|
{child->TraceDisconnect (subpath, cb);}
|
|
virtual void CollectSources (std::string path, const TraceContext &context,
|
|
SourceCollection *collection)
|
|
{
|
|
path.append ("/");
|
|
path.append (this->name);
|
|
TraceContext ctx = context;
|
|
ctx.Union (this->context);
|
|
this->child->GetTraceResolver ()->CollectSources (path, ctx, collection);
|
|
}
|
|
|
|
Ptr<Object> child;
|
|
} *item = new ChildCompositeItem ();
|
|
item->name = name;
|
|
item->context = context;
|
|
item->child = child;
|
|
AddItem (item);
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::SetParent (Ptr<TraceResolver> resolver)
|
|
{
|
|
m_parent = resolver;
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context)
|
|
{
|
|
NS_DEBUG ("connect path="<<path);
|
|
class ConnectOperation : public Operation
|
|
{
|
|
public:
|
|
ConnectOperation (const CallbackBase &cb, const TraceContext &context)
|
|
: m_cb (cb), m_context (context)
|
|
{}
|
|
virtual void Do (std::string subpath, CompositeItem *item) const
|
|
{
|
|
NS_DEBUG ("connect to path="<<subpath<<" name="<<item->name);
|
|
TraceContext context = m_context;
|
|
context.Union (item->context);
|
|
item->Connect (subpath, m_cb, context);
|
|
}
|
|
virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
|
|
{
|
|
if (parent != 0)
|
|
{
|
|
parent->Connect (path, m_cb, m_context);
|
|
}
|
|
}
|
|
private:
|
|
const CallbackBase &m_cb;
|
|
const TraceContext &m_context;
|
|
} operation = ConnectOperation (cb, context);
|
|
DoRecursiveOperation (path, operation);
|
|
}
|
|
void
|
|
CompositeTraceResolver::DoRecursiveOperation (std::string path,
|
|
const Operation &operation)
|
|
{
|
|
if (path == "")
|
|
{
|
|
return;
|
|
}
|
|
std::string id = GetElement (path);
|
|
std::string subpath = GetSubpath (path);
|
|
|
|
if (id == "*")
|
|
{
|
|
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
|
|
{
|
|
operation.Do (subpath, *i);
|
|
}
|
|
operation.DoParent (path, m_parent);
|
|
return;
|
|
}
|
|
std::string::size_type start, end;
|
|
start = id.find_first_of ("(", 0);
|
|
end = id.find_first_of (")", 0);
|
|
if (start != 0 || end != (id.size ()-1))
|
|
{
|
|
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
|
|
{
|
|
if ((*i)->name == id)
|
|
{
|
|
operation.Do (subpath, *i);
|
|
operation.DoParent (path, m_parent);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
std::list<std::string> names;
|
|
std::string alternatives = std::string (id, start+1, end-1);
|
|
std::string::size_type next_pos, cur_pos;
|
|
next_pos = 0;
|
|
cur_pos = 0;
|
|
while (true)
|
|
{
|
|
std::string element;
|
|
next_pos = alternatives.find ("|", cur_pos);
|
|
if (next_pos == std::string::npos)
|
|
{
|
|
element = std::string (alternatives, cur_pos, alternatives.size ());
|
|
names.push_back (element);
|
|
break;
|
|
}
|
|
element = std::string (alternatives, cur_pos, next_pos);
|
|
names.push_back (element);
|
|
cur_pos = next_pos + 1;
|
|
}
|
|
for (std::list<std::string>::const_iterator i = names.begin (); i != names.end (); i++)
|
|
{
|
|
for (TraceItems::const_iterator j = m_items.begin (); j != m_items.end (); j++)
|
|
{
|
|
if ((*j)->name == *i)
|
|
{
|
|
operation.Do (subpath, *j);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
operation.DoParent (path, m_parent);
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::Disconnect (std::string path, CallbackBase const &cb)
|
|
{
|
|
NS_DEBUG ("disconnect path="<<path);
|
|
class DisconnectOperation : public Operation
|
|
{
|
|
public:
|
|
DisconnectOperation (const CallbackBase &cb)
|
|
: m_cb (cb)
|
|
{}
|
|
virtual void Do (std::string subpath, CompositeItem *item) const
|
|
{
|
|
NS_DEBUG ("disconnect from path="<<subpath<<" name="<<item->name);
|
|
item->Disconnect (subpath, m_cb);
|
|
}
|
|
virtual void DoParent (std::string path, Ptr<TraceResolver> parent) const
|
|
{
|
|
if (parent != 0)
|
|
{
|
|
parent->Disconnect (path, m_cb);
|
|
}
|
|
}
|
|
private:
|
|
const CallbackBase &m_cb;
|
|
} operation = DisconnectOperation (cb);
|
|
DoRecursiveOperation (path, operation);
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolver::CollectSources (std::string path, const TraceContext &context,
|
|
SourceCollection *collection)
|
|
{
|
|
for (TraceItems::const_iterator i = m_items.begin (); i != m_items.end (); i++)
|
|
{
|
|
NS_DEBUG ("print " << (*i)->name);
|
|
(*i)->CollectSources (path, context, collection);
|
|
}
|
|
if (m_parent != 0)
|
|
{
|
|
m_parent->CollectSources (path, context, collection);
|
|
}
|
|
}
|
|
|
|
|
|
}//namespace ns3
|
|
|
|
#ifdef RUN_SELF_TESTS
|
|
|
|
#include "test.h"
|
|
#include "trace-context-element.h"
|
|
|
|
namespace ns3 {
|
|
|
|
class TraceSourceTest : public TraceContextElement
|
|
{
|
|
public:
|
|
enum Sources {
|
|
DOUBLEA,
|
|
DOUBLEB,
|
|
UINT16_T
|
|
};
|
|
static uint16_t GetUid (void)
|
|
{static uint16_t uid = AllocateUid<TraceSourceTest> ("TraceSourceTest"); return uid;}
|
|
void Print (std::ostream &os)
|
|
{os << "tracesource=";
|
|
if (m_sources == DOUBLEA) {os << "doubleA";}
|
|
else if (m_sources == DOUBLEB) {os << "doubleB";}
|
|
else if (m_sources == UINT16_T) {os << "uint16_t";}
|
|
}
|
|
std::string GetName (void) {return "TraceSourceTest";}
|
|
TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {}
|
|
TraceSourceTest (enum Sources sources) :m_sources (sources) {}
|
|
bool IsDoubleA (void) const {return m_sources == TraceSourceTest::DOUBLEA;}
|
|
bool IsDoubleB (void) const {return m_sources == TraceSourceTest::DOUBLEB;}
|
|
bool IsUint16 (void) const {return m_sources == TraceSourceTest::UINT16_T;}
|
|
private:
|
|
enum TraceSourceTest::Sources m_sources;
|
|
};
|
|
|
|
class SubTraceSourceTest : public TraceContextElement
|
|
{
|
|
public:
|
|
enum Sources {
|
|
INT,
|
|
};
|
|
static uint16_t GetUid (void)
|
|
{static uint16_t uid = AllocateUid<SubTraceSourceTest> ("SubTraceSourceTest"); return uid;}
|
|
void Print (std::ostream &os)
|
|
{os << "subtracesource=int";}
|
|
std::string GetName (void) const {return "SubTraceSourceTest";}
|
|
SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {}
|
|
SubTraceSourceTest (enum Sources sources) : m_sources (sources) {}
|
|
private:
|
|
enum Sources m_sources;
|
|
};
|
|
|
|
class CompositeTraceResolverTest : public Test
|
|
{
|
|
public:
|
|
CompositeTraceResolverTest ();
|
|
virtual ~CompositeTraceResolverTest ();
|
|
virtual bool RunTests (void);
|
|
private:
|
|
void TraceDouble (TraceContext const &context, double v);
|
|
void TraceInt (TraceContext const &context, int v);
|
|
Ptr<TraceResolver> CreateSubResolver ();
|
|
|
|
|
|
bool m_gotDoubleA;
|
|
bool m_gotDoubleB;
|
|
CallbackTraceSource<int> m_traceInt;
|
|
bool m_gotInt;
|
|
};
|
|
|
|
CompositeTraceResolverTest::CompositeTraceResolverTest ()
|
|
: Test ("CompositeTraceResolver")
|
|
{}
|
|
CompositeTraceResolverTest::~CompositeTraceResolverTest ()
|
|
{}
|
|
void
|
|
CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
|
|
{
|
|
TraceSourceTest source;
|
|
context.Get (source);
|
|
if (source.IsDoubleA ())
|
|
{
|
|
m_gotDoubleA = true;
|
|
}
|
|
else if (source.IsDoubleB ())
|
|
{
|
|
m_gotDoubleB = true;
|
|
}
|
|
else
|
|
{
|
|
NS_FATAL_ERROR ("should not get any other trace source in this sink");
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
CompositeTraceResolverTest::TraceInt (TraceContext const &context, int v)
|
|
{
|
|
m_gotInt = true;
|
|
}
|
|
|
|
Ptr<TraceResolver>
|
|
CompositeTraceResolverTest::CreateSubResolver (void)
|
|
{
|
|
Ptr<CompositeTraceResolver> subresolver = Create<CompositeTraceResolver> ();
|
|
subresolver->AddSource ("trace-int", TraceDoc ("test source"), m_traceInt,
|
|
SubTraceSourceTest (SubTraceSourceTest::INT));
|
|
return subresolver;
|
|
}
|
|
bool
|
|
CompositeTraceResolverTest::RunTests (void)
|
|
{
|
|
bool ok = true;
|
|
|
|
CallbackTraceSource<double> traceDoubleA;
|
|
CallbackTraceSource<double> traceDoubleB;
|
|
TraceContext context;
|
|
|
|
CompositeTraceResolver resolver;
|
|
|
|
resolver.AddSource ("trace-double-a", TraceDoc ("test source"), traceDoubleA,
|
|
TraceSourceTest (TraceSourceTest::DOUBLEA));
|
|
resolver.AddSource ("trace-double-b", TraceDoc ("test source"), traceDoubleB,
|
|
TraceSourceTest (TraceSourceTest::DOUBLEB));
|
|
|
|
resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
|
|
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
traceDoubleA (0);
|
|
if (!m_gotDoubleA || m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
m_gotDoubleA = false;
|
|
traceDoubleA (0);
|
|
traceDoubleB (0);
|
|
if (!m_gotDoubleA || !m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
|
|
resolver.Disconnect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
|
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
traceDoubleA (0);
|
|
traceDoubleB (0);
|
|
if (m_gotDoubleA || m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
resolver.Connect ("/trace-double-a",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
traceDoubleA (0);
|
|
traceDoubleB (0);
|
|
if (!m_gotDoubleA || m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
resolver.Disconnect ("/trace-double-a",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
|
|
|
resolver.Connect ("/(trace-double-a)",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
traceDoubleA (0);
|
|
traceDoubleB (0);
|
|
if (!m_gotDoubleA || m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
resolver.Disconnect ("/trace-double-a",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
|
|
|
resolver.Connect ("/(trace-double-a|trace-double-b)",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this), TraceContext ());
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
traceDoubleA (0);
|
|
traceDoubleB (0);
|
|
if (!m_gotDoubleA || !m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
resolver.Disconnect ("/trace-double-a",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
traceDoubleA (0);
|
|
traceDoubleB (0);
|
|
if (m_gotDoubleA || !m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
|
|
resolver.Disconnect ("/(trace-double-a|trace-double-b)",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
|
|
m_gotDoubleA = false;
|
|
m_gotDoubleB = false;
|
|
traceDoubleA (0);
|
|
traceDoubleB (0);
|
|
if (m_gotDoubleA || m_gotDoubleB)
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
resolver.Add ("subresolver",
|
|
MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this));
|
|
|
|
resolver.Connect ("/subresolver/trace-int",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
|
|
m_gotInt = false;
|
|
m_traceInt (1);
|
|
if (!m_gotInt)
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
resolver.Disconnect ("/subresolver/trace-int",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
|
|
m_gotInt = false;
|
|
m_traceInt (1);
|
|
if (m_gotInt)
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
resolver.Connect ("/*/trace-int",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceInt, this), TraceContext ());
|
|
m_gotInt = false;
|
|
m_traceInt (1);
|
|
if (!m_gotInt)
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
resolver.Disconnect ("/subresolver/trace-int",
|
|
MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
|
|
m_gotInt = false;
|
|
m_traceInt (1);
|
|
if (m_gotInt)
|
|
{
|
|
ok = false;
|
|
}
|
|
|
|
SVTraceSource<uint16_t> source;
|
|
|
|
resolver.AddSource ("uint16_t", TraceDoc ("test source"), source, TraceSourceTest (TraceSourceTest::UINT16_T));
|
|
|
|
|
|
return ok;
|
|
}
|
|
|
|
static CompositeTraceResolverTest g_compositeTraceResolverTest;
|
|
|
|
}//namespace ns3
|
|
|
|
|
|
#endif /* RUN_SELF_TESTS */
|