src/core/array-trace-resolver.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sun, 02 Mar 2008 21:12:21 +0100
changeset 2532 86a40c7cbfe9
parent 2230 9f13ac3291e0
permissions -rw-r--r--
register and unregister the NodeList as a config root namespace

/* -*- 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 "array-trace-resolver.h"

namespace ns3 {

ArrayTraceResolverMatcher::ArrayTraceResolverMatcher (std::string element)
  : m_element (element)
{}
bool 
ArrayTraceResolverMatcher::Matches (uint32_t i) const
{
  if (m_element == "*")
    {
      return true;
    }
  std::string::size_type tmp;
  tmp = m_element.find ("|");
  if (tmp != std::string::npos)
    {
      std::string left = m_element.substr (0, tmp-0);
      std::string right = m_element.substr (tmp+1, m_element.size () - (tmp + 1));
      ArrayTraceResolverMatcher matcher = ArrayTraceResolverMatcher (left);
      if (matcher.Matches (i))
	{
	  return true;
	}
      matcher = ArrayTraceResolverMatcher (right);
      if (matcher.Matches (i))
	{
	  return true;
	}
      return false;
    }
  std::string::size_type leftBracket = m_element.find ("[");
  std::string::size_type rightBracket = m_element.find ("]");
  std::string::size_type dash = m_element.find ("-");
  if (leftBracket == 0 && rightBracket == m_element.size () - 1 &&
      dash > leftBracket && dash < rightBracket)
    {
      std::string lowerBound = m_element.substr (leftBracket + 1, dash - (leftBracket + 1));
      std::string upperBound = m_element.substr (dash + 1, rightBracket - (dash + 1));
      uint32_t min;
      uint32_t max;
      if (StringToUint32 (lowerBound, &min) && 
	  StringToUint32 (upperBound, &max) &&
	  i >= min && i <= max)
        {
          return true;
        }
      else
	{
	  return false;
	}
    }
  uint32_t value;
  if (StringToUint32 (m_element, &value) &&
      i == value)
    {
      return true;
    }
  return false;
}

bool
ArrayTraceResolverMatcher::StringToUint32 (std::string str, uint32_t *value) const
{
  std::istringstream iss;
  iss.str (str);
  iss >> (*value);
  return !iss.bad () && !iss.fail ();
}

}//namespace ns3


#ifdef RUN_SELF_TESTS

#include <stdarg.h>
#include "test.h"
#include "object.h"
#include "array-trace-resolver.h"
#include "callback-trace-source.h"
#include "composite-trace-resolver.h"

namespace ns3 {

class ObjectTraceTesterIndex : public TraceContextElement
{
public:
  ObjectTraceTesterIndex ();
  ObjectTraceTesterIndex (uint32_t index);
  void Print (std::ostream &os);
  static uint16_t GetUid (void);
  uint32_t Get (void) const;
  std::string GetTypeName (void) const;
private:
  uint32_t m_index;
};


ObjectTraceTesterIndex::ObjectTraceTesterIndex ()
  : m_index (0)
{}
ObjectTraceTesterIndex::ObjectTraceTesterIndex (uint32_t index)
  : m_index (index)
{}
void 
ObjectTraceTesterIndex::Print (std::ostream &os)
{
  os << "nodeid=" << m_index;
}
uint16_t 
ObjectTraceTesterIndex::GetUid (void)
{
  static uint16_t uid = AllocateUid<ObjectTraceTesterIndex> ("ObjectTraceTesterIndex");
  return uid;
}
uint32_t 
ObjectTraceTesterIndex::Get (void) const
{
  return m_index;
}
std::string 
ObjectTraceTesterIndex::GetTypeName (void) const
{
  return "ns3::ObjectTraceTesterIndex";
}


class ObjectTraceTester : public Object
{
public:
  void Do (uint32_t i);
protected:
  virtual Ptr<TraceResolver> GetTraceResolver (void) const;
private:
  CallbackTraceSource<uint32_t> m_test;
};

void 
ObjectTraceTester::Do (uint32_t i)
{
  m_test (i);
}

Ptr<TraceResolver>
ObjectTraceTester::GetTraceResolver (void) const
{
  Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
  resolver->AddSource ("test", 
		       TraceDoc ("Test"),
		       m_test);
  resolver->SetParentResolver (Object::GetTraceResolver ());
  return resolver;
}

class ArrayTraceResolverTest : public Test
{
public:
  ArrayTraceResolverTest ();
  virtual bool RunTests (void);
private:
  bool RunOne (uint32_t n, std::string str, 
	       uint32_t nExpected, ...);
  void OneItem (const TraceContext &context,
		uint32_t i);

  typedef std::vector<uint32_t> Got;
  Got m_got;
};

ArrayTraceResolverTest::ArrayTraceResolverTest ()
  : Test ("ArrayTraceResolver")
{}
bool
ArrayTraceResolverTest::RunOne (uint32_t n, std::string str, 
				uint32_t nExpected, ...)
{
  bool result = true;
  std::vector<uint32_t> expected;
  va_list ap;
  va_start (ap, nExpected);
  for (uint32_t k = 0; k < nExpected; k++)
    {
      uint32_t v = va_arg (ap, uint32_t);
      expected.push_back (v);
    }
  va_end (ap);
  std::sort (expected.begin (), expected.end ());
  std::sort (m_got.begin (), m_got.end ());

  std::vector<Ptr<ObjectTraceTester> > vec;
  for (uint32_t i = 0; i < n; i++)
    {
      vec.push_back (CreateObject<ObjectTraceTester> ());
    }
  ArrayTraceResolver<ObjectTraceTesterIndex> resolver;
  resolver.SetIterators (vec.begin (), vec.end ());

  TraceContext context;
  resolver.Connect (str, MakeCallback (&ArrayTraceResolverTest::OneItem, this), context);
  uint32_t l = 0;
  for (std::vector<Ptr<ObjectTraceTester> >::const_iterator j = vec.begin (); j != vec.end (); j++)
    {
      (*j)->Do (l);
      l++;
    }
  NS_TEST_ASSERT_EQUAL (m_got.size (), expected.size ());
  for (uint32_t m = 0; m < expected.size (); m++)
    {
      NS_TEST_ASSERT_EQUAL (m_got[m], expected[m]);
    }
  m_got.clear ();
  resolver.Disconnect (str, MakeCallback (&ArrayTraceResolverTest::OneItem, this));
  for (std::vector<Ptr<ObjectTraceTester> >::const_iterator j = vec.begin (); j != vec.end (); j++)
    {
      (*j)->Do (l);
      l++;
    }
  NS_TEST_ASSERT_EQUAL (m_got.size (), 0);
  m_got.clear ();

  return result;
}
void
ArrayTraceResolverTest::OneItem (const TraceContext &context,
				 uint32_t i)
{
  ObjectTraceTesterIndex index;
  bool found = context.GetElement (index);
  if (!found)
    {
      return;
    }
  if (index.Get () != i)
    {
      return;
    }
  m_got.push_back (i);
}

bool 
ArrayTraceResolverTest::RunTests (void)
{
  bool result = true;

  NS_TEST_ASSERT (RunOne (0, "/*/test", 0));
  NS_TEST_ASSERT (RunOne (1, "/*/test", 1, 0));
  NS_TEST_ASSERT (RunOne (1, "/0/test", 1, 0));
  NS_TEST_ASSERT (RunOne (1, "/[0-0]/test", 1, 0));
  NS_TEST_ASSERT (RunOne (1, "/0|0/test", 1, 0));
  NS_TEST_ASSERT (RunOne (2, "/*/test", 2, 0, 1));
  NS_TEST_ASSERT (RunOne (2, "/0|1/test", 2, 0, 1));
  NS_TEST_ASSERT (RunOne (2, "/1/test", 1, 1));
  NS_TEST_ASSERT (RunOne (2, "/|1|/test", 1, 1));
  NS_TEST_ASSERT (RunOne (2, "/0/test", 1, 0));
  NS_TEST_ASSERT (RunOne (2, "/0|/test", 1, 0));
  NS_TEST_ASSERT (RunOne (2, "/|0/test", 1, 0));
  NS_TEST_ASSERT (RunOne (2, "/[0-1]/test", 2, 0, 1));
  NS_TEST_ASSERT (RunOne (2, "/[0-0]/test", 1, 0));
  NS_TEST_ASSERT (RunOne (2, "/[1-1]/test", 1, 1));
  NS_TEST_ASSERT (RunOne (2, "/0|[1-1]/test", 2, 0, 1));
  NS_TEST_ASSERT (RunOne (3, "/1|0/test", 2, 0, 1));
  NS_TEST_ASSERT (RunOne (3, "/2|0/test", 2, 0, 2));
  NS_TEST_ASSERT (RunOne (3, "/2|1/test", 2, 1, 2));
  NS_TEST_ASSERT (RunOne (3, "/[0-1]/test", 2, 0, 1));
  NS_TEST_ASSERT (RunOne (3, "/[1-2]/test", 2, 1, 2));
  NS_TEST_ASSERT (RunOne (3, "/[0-2]/test", 3, 0, 1, 2));
  NS_TEST_ASSERT (RunOne (3, "/[1-2]|0/test", 3, 0, 1, 2));
  NS_TEST_ASSERT (RunOne (3, "/[1-1]|0|[2-2]/test", 3, 0, 1, 2));
  NS_TEST_ASSERT (RunOne (3, "/[1-2]||/test", 2, 1, 2));
  NS_TEST_ASSERT (RunOne (3, "/[1-2]||/test", 2, 2, 1));
  NS_TEST_ASSERT (RunOne (3, "/||||/test", 0));
  NS_TEST_ASSERT (RunOne (20, "/[5-10]|[2-3]|[15-17]/test", 11, 2, 3, 5, 6, 7, 8, 9, 10, 15, 16, 17));
  NS_TEST_ASSERT (RunOne (3, "/[1-2]|[0-1]/test", 3, 0, 1, 2));

  return result;
}



static ArrayTraceResolverTest g_arrayTraceResolverTest;


} // namespace ns3

#endif /* RUN_SELF_TESTS */