445 lines
11 KiB
C++
445 lines
11 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2009 The Georgia Institute of Technology
|
|
*
|
|
* 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
|
|
*
|
|
* Authors: Josh Pelkey <jpelkey@gatech.edu>
|
|
*/
|
|
|
|
#include "ns3/log.h"
|
|
#include "ns3/fatal-error.h"
|
|
|
|
#include "nix-vector.h"
|
|
|
|
NS_LOG_COMPONENT_DEFINE ("NixVector");
|
|
|
|
namespace ns3 {
|
|
|
|
typedef std::vector<uint32_t> NixBits_t; //!< typedef for the nixVector
|
|
|
|
NixVector::NixVector ()
|
|
: m_nixVector (0),
|
|
m_used (0),
|
|
m_currentVectorBitSize (0),
|
|
m_totalBitSize (0)
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
m_nixVector.push_back (0);
|
|
}
|
|
|
|
NixVector::~NixVector ()
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
}
|
|
|
|
NixVector::NixVector (const NixVector &o)
|
|
: m_nixVector (o.m_nixVector),
|
|
m_used (o.m_used),
|
|
m_currentVectorBitSize (o.m_currentVectorBitSize),
|
|
m_totalBitSize (o.m_totalBitSize)
|
|
{
|
|
}
|
|
|
|
NixVector &
|
|
NixVector::operator = (const NixVector &o)
|
|
{
|
|
if (this == &o)
|
|
{
|
|
return *this;
|
|
}
|
|
m_nixVector = o.m_nixVector;
|
|
m_used = o.m_used;
|
|
m_currentVectorBitSize = o.m_currentVectorBitSize;
|
|
m_totalBitSize = o.m_totalBitSize;
|
|
return *this;
|
|
}
|
|
|
|
Ptr<NixVector>
|
|
NixVector::Copy (void) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
// we need to invoke the copy constructor directly
|
|
// rather than calling Create because the copy constructor
|
|
// is private.
|
|
return Ptr<NixVector> (new NixVector (*this), false);
|
|
}
|
|
|
|
/* For printing the nix vector */
|
|
std::ostream & operator << (std::ostream &os, const NixVector &nix)
|
|
{
|
|
nix.DumpNixVector (os);
|
|
return os;
|
|
}
|
|
|
|
void
|
|
NixVector::AddNeighborIndex (uint32_t newBits, uint32_t numberOfBits)
|
|
{
|
|
NS_LOG_FUNCTION (this << newBits << numberOfBits);
|
|
|
|
if (numberOfBits > 32)
|
|
{
|
|
NS_FATAL_ERROR ("Can't add more than 32 bits to a nix-vector at one time");
|
|
}
|
|
|
|
// Check to see if the number
|
|
// of new bits forces the creation of
|
|
// a new entry into the NixVector vector
|
|
// i.e., we will overflow int o.w.
|
|
if (m_currentVectorBitSize + numberOfBits > 32)
|
|
{
|
|
if (m_currentVectorBitSize == 32)
|
|
{
|
|
// can't add any more to this vector, so
|
|
// start a new one
|
|
m_nixVector.push_back (newBits);
|
|
|
|
// also reset number of bits in
|
|
// m_currentVectorBitSize
|
|
// because we are working with a new
|
|
// entry in the vector
|
|
m_currentVectorBitSize = numberOfBits;
|
|
m_totalBitSize += numberOfBits;
|
|
}
|
|
else
|
|
{
|
|
// Put what we can in the remaining portion of the
|
|
// vector entry
|
|
uint32_t tempBits = newBits;
|
|
tempBits = newBits << m_currentVectorBitSize;
|
|
tempBits |= m_nixVector.back ();
|
|
m_nixVector.back () = tempBits;
|
|
|
|
// Now start a new vector entry
|
|
// and push the remaining bits
|
|
// there
|
|
newBits = newBits >> (32 - m_currentVectorBitSize);
|
|
m_nixVector.push_back (newBits);
|
|
|
|
// also reset number of bits in
|
|
// m_currentVectorBitSize
|
|
// because we are working with a new
|
|
// entry in the vector
|
|
m_currentVectorBitSize = (numberOfBits - (32 - m_currentVectorBitSize));
|
|
m_totalBitSize += numberOfBits;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Shift over the newbits by the
|
|
// number of current bits. This allows
|
|
// us to logically OR with the present
|
|
// NixVector, resulting in the new
|
|
// NixVector
|
|
newBits = newBits << m_currentVectorBitSize;
|
|
newBits |= m_nixVector.back ();
|
|
|
|
// Now insert the new NixVector and
|
|
// increment number of bits for
|
|
// m_currentVectorBitSize and m_totalBitSize
|
|
// accordingly
|
|
m_nixVector.back () = newBits;
|
|
m_currentVectorBitSize += numberOfBits;
|
|
m_totalBitSize += numberOfBits;
|
|
}
|
|
}
|
|
|
|
uint32_t
|
|
NixVector::ExtractNeighborIndex (uint32_t numberOfBits)
|
|
{
|
|
NS_LOG_FUNCTION (this << numberOfBits);
|
|
|
|
if (numberOfBits > 32)
|
|
{
|
|
NS_FATAL_ERROR ("Can't extract more than 32 bits to a nix-vector at one time");
|
|
}
|
|
|
|
uint32_t vectorIndex = 0;
|
|
uint32_t extractedBits = 0;
|
|
uint32_t totalRemainingBits = GetRemainingBits ();
|
|
|
|
if (numberOfBits > totalRemainingBits)
|
|
{
|
|
NS_FATAL_ERROR ("You've tried to extract too many bits of the Nix-vector, " << this << ". NumberBits: "
|
|
<< numberOfBits << " Remaining: " << totalRemainingBits);
|
|
}
|
|
|
|
if (numberOfBits <= 0)
|
|
{
|
|
NS_FATAL_ERROR ("You've specified a number of bits for Nix-vector <= 0!");
|
|
}
|
|
|
|
// First determine where in the NixVector
|
|
// vector we need to extract which depends
|
|
// on the number of used bits and the total
|
|
// number of bits
|
|
vectorIndex = ((totalRemainingBits-1) / 32);
|
|
|
|
// Next, determine if this extraction will
|
|
// span multiple vector entries
|
|
if (vectorIndex > 0) // we could span more than one
|
|
{
|
|
if ((numberOfBits-1) > ((totalRemainingBits-1) % 32)) // we do span more than one
|
|
{
|
|
extractedBits = m_nixVector.at (vectorIndex) << (32 - (totalRemainingBits % 32));
|
|
extractedBits = extractedBits >> ((32 - (totalRemainingBits % 32))
|
|
- (numberOfBits - (totalRemainingBits % 32)));
|
|
extractedBits |= (m_nixVector.at (vectorIndex-1)
|
|
>> (32 - (numberOfBits - (totalRemainingBits % 32))));
|
|
m_used += numberOfBits;
|
|
return extractedBits;
|
|
}
|
|
}
|
|
|
|
// we don't span more than one
|
|
extractedBits = m_nixVector.at (vectorIndex) << (32 - (totalRemainingBits % 32));
|
|
extractedBits = extractedBits >> (32 - (numberOfBits));
|
|
m_used += numberOfBits;
|
|
return extractedBits;
|
|
}
|
|
|
|
uint32_t
|
|
NixVector::GetSerializedSize (void) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
uint32_t totalSizeInBytes = 0;
|
|
totalSizeInBytes = sizeof (m_used) + sizeof (m_currentVectorBitSize) +
|
|
sizeof (m_totalBitSize) + (4 * m_nixVector.size ());
|
|
|
|
return totalSizeInBytes;
|
|
}
|
|
|
|
uint32_t
|
|
NixVector::Serialize (uint32_t* buffer, uint32_t maxSize) const
|
|
{
|
|
NS_LOG_FUNCTION (this << buffer << maxSize);
|
|
uint32_t* p = buffer;
|
|
uint32_t size = 0;
|
|
|
|
if (size + 4 <= maxSize)
|
|
{
|
|
size += 4;
|
|
// grab number of used bits
|
|
*p++ = m_used;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (size + 4 <= maxSize)
|
|
{
|
|
size += 4;
|
|
// grab number of current used bits
|
|
// for the front vector
|
|
*p++ = m_currentVectorBitSize;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (size + 4 <= maxSize)
|
|
{
|
|
size += 4;
|
|
// grab total bit size
|
|
*p++ = m_totalBitSize;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
for (uint32_t j = 0; j < m_nixVector.size (); j++)
|
|
{
|
|
if (size + 4 <= maxSize)
|
|
{
|
|
size += 4;
|
|
*p++ = m_nixVector.at (j);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Serialized successfully
|
|
return 1;
|
|
}
|
|
|
|
uint32_t
|
|
NixVector::Deserialize (const uint32_t* buffer, uint32_t size)
|
|
{
|
|
NS_LOG_FUNCTION (this << buffer << size);
|
|
const uint32_t* p = buffer;
|
|
uint32_t sizeCheck = size - 4;
|
|
|
|
NS_ASSERT (sizeCheck >= 4);
|
|
m_used = *p++;
|
|
sizeCheck -= 4;
|
|
|
|
NS_ASSERT (sizeCheck >= 4);
|
|
m_currentVectorBitSize = *p++;
|
|
sizeCheck -= 4;
|
|
|
|
NS_ASSERT (sizeCheck >= 4);
|
|
m_totalBitSize = *p++;
|
|
sizeCheck -= 4;
|
|
|
|
// make sure the nix-vector
|
|
// is empty
|
|
m_nixVector.clear ();
|
|
while (sizeCheck > 0)
|
|
{
|
|
NS_ASSERT (sizeCheck >= 4);
|
|
uint32_t nix = *p++;
|
|
m_nixVector.push_back (nix);
|
|
sizeCheck -= 4;
|
|
}
|
|
|
|
NS_ASSERT (sizeCheck == 0);
|
|
|
|
// return zero if an entire nix-vector was
|
|
// not deserialized
|
|
return (sizeCheck != 0) ? 0 : 1;
|
|
}
|
|
|
|
void
|
|
NixVector::DumpNixVector (std::ostream &os) const
|
|
{
|
|
NS_LOG_FUNCTION (this << &os);
|
|
uint32_t i = m_nixVector.size ();
|
|
std::vector<uint32_t>::const_reverse_iterator rIter;
|
|
for (rIter = m_nixVector.rbegin (); rIter != m_nixVector.rend (); rIter++)
|
|
{
|
|
uint32_t numBits = BitCount (*rIter);
|
|
|
|
// all this work just to get the nix
|
|
// vector to print out neat
|
|
|
|
// if it's not the first entry in the vector,
|
|
// we may have to add some zeros and fill
|
|
// out the vector
|
|
if (m_totalBitSize > ((sizeof (uint32_t)*8) * i))
|
|
{
|
|
PrintDec2BinNixFill (*rIter,numBits,os);
|
|
}
|
|
else if (m_totalBitSize%32 == 0)
|
|
{
|
|
PrintDec2BinNix (*rIter,32,os);
|
|
}
|
|
else
|
|
{
|
|
PrintDec2BinNix (*rIter,m_totalBitSize%32,os);
|
|
}
|
|
|
|
i--;
|
|
|
|
if (i > 0)
|
|
{
|
|
os << "--";
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t
|
|
NixVector::GetRemainingBits (void)
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
return (m_totalBitSize - m_used);
|
|
}
|
|
|
|
uint32_t
|
|
NixVector::BitCount (uint32_t numberOfNeighbors) const
|
|
{
|
|
NS_LOG_FUNCTION (this << numberOfNeighbors);
|
|
|
|
// Given the numberOfNeighbors, return the number
|
|
// of bits needed (essentially, log2(numberOfNeighbors-1)
|
|
uint32_t bitCount = 0;
|
|
|
|
if (numberOfNeighbors < 2)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
for (numberOfNeighbors -= 1; numberOfNeighbors != 0; numberOfNeighbors >>= 1)
|
|
{
|
|
bitCount++;
|
|
}
|
|
return bitCount;
|
|
}
|
|
}
|
|
|
|
void
|
|
NixVector::PrintDec2BinNix (uint32_t decimalNum, uint32_t bitCount, std::ostream &os) const
|
|
{
|
|
NS_LOG_FUNCTION (this << decimalNum << bitCount << &os);
|
|
if(decimalNum == 0)
|
|
{
|
|
for (; bitCount > 0; bitCount--)
|
|
{
|
|
os << 0;
|
|
}
|
|
return;
|
|
}
|
|
if(decimalNum == 1)
|
|
{
|
|
for (; bitCount > 1; bitCount--)
|
|
{
|
|
os << 0;
|
|
}
|
|
os << 1;
|
|
}
|
|
else
|
|
{
|
|
PrintDec2BinNix (decimalNum / 2,bitCount-1, os);
|
|
os << decimalNum % 2;
|
|
}
|
|
}
|
|
|
|
void
|
|
NixVector::PrintDec2BinNixFill (uint32_t decimalNum, uint32_t bitCount, std::ostream &os) const
|
|
{
|
|
NS_LOG_FUNCTION (this << decimalNum << bitCount << &os);
|
|
if(decimalNum == 0)
|
|
{
|
|
os << 0;
|
|
return;
|
|
}
|
|
if(decimalNum == 1)
|
|
{
|
|
// check to see if we need to
|
|
// print out some zeros at the
|
|
// beginning of the nix vector
|
|
if ((uint32_t)(sizeof (uint32_t)*8) > bitCount)
|
|
{
|
|
for (uint32_t i = ((sizeof (uint32_t)*8)-bitCount); i > 0; i--)
|
|
{
|
|
os << 0;
|
|
}
|
|
}
|
|
os << 1;
|
|
}
|
|
else
|
|
{
|
|
PrintDec2BinNixFill (decimalNum / 2, bitCount, os);
|
|
os << decimalNum % 2;
|
|
}
|
|
}
|
|
|
|
} // namespace ns3
|