Files
unison/src/core/trace-context.cc
2007-08-30 14:35:44 +02:00

460 lines
9.5 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 "trace-context.h"
#include "trace-context-element.h"
#include "assert.h"
namespace ns3 {
TraceContext::Iterator::Iterator ()
: m_buffer (0),
m_size (0),
m_current (0)
{}
TraceContext::Iterator::Iterator (uint8_t *buffer, uint16_t size)
: m_buffer (buffer),
m_size (size),
m_current (0)
{
m_uid = m_buffer[m_current];
}
bool
TraceContext::Iterator::IsLast (void) const
{
if (m_buffer == 0 || m_uid == 0 || m_current >= m_size)
{
return true;
}
return false;
}
void
TraceContext::Iterator::Next (void)
{
if (m_buffer == 0)
{
return;
}
if (m_uid == 0)
{
return;
}
else
{
uint8_t size = ElementRegistry::GetSize (m_uid);
m_current += 1 + size;
}
m_uid = m_buffer[m_current];
}
std::string
TraceContext::Iterator::Get (void) const
{
std::string name = ElementRegistry::GetTypeName (m_uid);
return name;
}
TraceContext::TraceContext ()
: m_data (0)
{}
TraceContext::TraceContext (TraceContext const &o)
: m_data (o.m_data)
{
if (m_data != 0)
{
m_data->count++;
}
}
TraceContext const &
TraceContext::operator = (TraceContext const &o)
{
if (m_data != 0)
{
m_data->count--;
if (m_data->count == 0)
{
uint8_t *buffer = (uint8_t *)m_data;
delete [] buffer;
}
}
m_data = o.m_data;
if (m_data != 0)
{
m_data->count++;
}
return *this;
}
TraceContext::~TraceContext ()
{
if (m_data != 0)
{
m_data->count--;
if (m_data->count == 0)
{
uint8_t *buffer = (uint8_t *)m_data;
delete [] buffer;
}
}
}
void
TraceContext::Union (TraceContext const &o)
{
if (o.m_data == 0)
{
return;
}
uint16_t currentUid;
uint16_t i = 0;
while (i < o.m_data->size)
{
currentUid = o.m_data->data[i];
uint8_t size = ElementRegistry::GetSize (currentUid);
uint8_t *selfBuffer = CheckPresent (currentUid);
uint8_t *otherBuffer = &(o.m_data->data[i+1]);
if (selfBuffer != 0)
{
if (memcmp (selfBuffer, otherBuffer, size) != 0)
{
NS_FATAL_ERROR ("You cannot add TraceContexts which "<<
"have different values stored in them.");
}
}
else
{
DoAdd (currentUid, otherBuffer);
}
i += 1 + size;
}
}
uint8_t *
TraceContext::CheckPresent (uint8_t uid) const
{
if (m_data == 0)
{
return false;
}
uint8_t currentUid;
uint16_t i = 0;
do {
currentUid = m_data->data[i];
uint8_t size = ElementRegistry::GetSize (currentUid);
if (currentUid == uid)
{
return &m_data->data[i+1];
}
i += 1 + size;
} while (i < m_data->size && currentUid != 0);
return 0;
}
bool
TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
{
NS_ASSERT (uid != 0);
uint8_t size = ElementRegistry::GetSize (uid);
uint8_t *present = CheckPresent (uid);
if (present != 0) {
if (memcmp (present, buffer, size) == 0)
{
return true;
}
else
{
return false;
}
}
if (m_data == 0)
{
uint16_t newSize = 1 + size;
uint16_t allocatedSize;
if (newSize > 4)
{
allocatedSize = sizeof (struct Data) + newSize - 4;
}
else
{
allocatedSize = sizeof (struct Data);
}
struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
data->size = newSize;
data->count = 1;
data->data[0] = uid;
memcpy (data->data + 1, buffer, size);
m_data = data;
}
else
{
uint16_t newSize = m_data->size + 1 + size;
uint16_t allocatedSize;
if (newSize > 4)
{
allocatedSize = sizeof (struct Data) + newSize - 4;
}
else
{
allocatedSize = sizeof (struct Data);
}
struct Data *data = (struct Data *) (new uint8_t [allocatedSize] ());
data->size = newSize;
data->count = 1;
memcpy (data->data, m_data->data, m_data->size);
data->data[m_data->size] = uid;
memcpy (data->data + m_data->size + 1, buffer, size);
m_data->count--;
if (m_data->count == 0)
{
uint8_t *buffer = (uint8_t *)m_data;
delete [] buffer;
}
m_data = data;
}
return true;
}
bool
TraceContext::DoGet (uint8_t uid, uint8_t *buffer) const
{
if (m_data == 0)
{
return false;
}
uint8_t currentUid;
uint16_t i = 0;
do {
currentUid = m_data->data[i];
uint8_t size = ElementRegistry::GetSize (currentUid);
if (currentUid == uid)
{
memcpy (buffer, &m_data->data[i+1], size);
return true;
}
i += 1 + size;
} while (i < m_data->size && currentUid != 0);
return false;
}
void
TraceContext::Print (std::ostream &os) const
{
if (m_data == 0)
{
return;
}
uint8_t currentUid;
uint16_t i = 0;
do {
currentUid = m_data->data[i];
uint8_t size = ElementRegistry::GetSize (currentUid);
uint8_t *instance = &m_data->data[i+1];
ElementRegistry::Print (currentUid, instance, os);
i += 1 + size;
if (i < m_data->size && currentUid != 0)
{
os << " ";
}
else
{
break;
}
} while (true);
}
TraceContext::Iterator
TraceContext::Begin (void) const
{
if (m_data == 0)
{
return Iterator ();
}
return Iterator (m_data->data, m_data->size);
}
void
TraceContext::PrintAvailable (std::ostream &os, std::string separator) const
{
if (m_data == 0)
{
return;
}
uint8_t currentUid;
uint16_t i = 0;
do {
currentUid = m_data->data[i];
uint8_t size = ElementRegistry::GetSize (currentUid);
os << ElementRegistry::GetTypeName (currentUid);
i += 1 + size;
if (i < m_data->size && currentUid != 0)
{
os << separator;
}
else
{
break;
}
} while (true);
}
bool
TraceContext::IsSimilar (const TraceContext &o) const
{
if (m_data == 0 && o.m_data == 0)
{
return true;
}
if ((m_data != 0 && o.m_data == 0) ||
(m_data == 0 && o.m_data != 0))
{
return false;
}
uint8_t myCurrentUid;
uint16_t myI = 0;
uint8_t otherCurrentUid;
uint16_t otherI = 0;
myCurrentUid = m_data->data[myI];
otherCurrentUid = o.m_data->data[otherI];
while (myCurrentUid == otherCurrentUid &&
myCurrentUid != 0 &&
otherCurrentUid != 0 &&
myI < m_data->size &&
otherI < o.m_data->size)
{
uint8_t mySize = ElementRegistry::GetSize (myCurrentUid);
uint8_t otherSize = ElementRegistry::GetSize (otherCurrentUid);
myI += 1 + mySize;
otherI += 1 + otherSize;
myCurrentUid = m_data->data[myI];
otherCurrentUid = o.m_data->data[otherI];
}
if (myCurrentUid == 0 && otherCurrentUid == 0)
{
return true;
}
else
{
return false;
}
}
std::ostream& operator<< (std::ostream& os, const TraceContext &context)
{
context.Print (os);
return os;
}
}//namespace ns3
#include "test.h"
#include <sstream>
namespace ns3 {
template <int N>
class Ctx : public TraceContextElement
{
public:
static uint16_t GetUid (void) {static uint16_t uid = AllocateUid<Ctx<N> > (GetTypeName ()); return uid;}
static std::string GetTypeName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();}
Ctx () : m_v (0) {}
Ctx (int v) : m_v (v) {}
void Print (std::ostream &os) {os << N;}
int Get (void) const { return N;}
private:
int m_v;
};
class TraceContextTest : public Test
{
public:
TraceContextTest ();
virtual bool RunTests (void);
};
TraceContextTest::TraceContextTest ()
: Test ("TraceContext")
{}
bool
TraceContextTest::RunTests (void)
{
bool ok = true;
TraceContext ctx;
Ctx<0> v0;
Ctx<0> v01 = Ctx<0> (1);
Ctx<1> v1;
Ctx<2> v2;
Ctx<3> v3;
if (ctx.SafeGet (v0))
{
ok = false;
}
ctx.AddElement (v0);
ctx.AddElement (v0);
if (ctx.SafeAdd (v01))
{
ok = false;
}
ctx.GetElement (v0);
ctx.AddElement (v1);
ctx.GetElement (v1);
ctx.GetElement (v0);
ctx.GetElement (v1);
TraceContext copy = ctx;
ctx.GetElement (v0);
ctx.GetElement (v1);
copy.GetElement (v0);
copy.GetElement (v1);
copy.AddElement (v2);
copy.GetElement (v0);
copy.GetElement (v1);
copy.GetElement (v2);
ctx.AddElement (v3);
ctx.GetElement (v0);
ctx.GetElement (v1);
ctx.GetElement (v3);
if (ctx.SafeGet (v2))
{
ok = false;
}
if (copy.SafeGet (v3))
{
ok = false;
}
ctx.Union (copy);
ctx.GetElement (v2);
if (copy.SafeGet (v3))
{
ok = false;
}
copy.Union (ctx);
copy.GetElement (v3);
return ok;
}
static TraceContextTest g_traceContextTest;
}//namespace ns3