src/common/buffer.cc
author Nicola Baldo <nbaldo@cttc.es>
Thu Aug 13 09:36:16 2009 +0200 (2009-08-13)
changeset 4708 b251fb79becb
parent 4518 31f2881aa214
child 5261 7ccbdea36ec8
permissions -rw-r--r--
bug 639: Buffer::CopyData is buggy.
mathieu@150
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
mathieu@9
     2
/*
mathieu@1461
     3
 * Copyright (c) 2005,2006,2007 INRIA
mathieu@9
     4
 *
mathieu@9
     5
 * This program is free software; you can redistribute it and/or modify
mathieu@9
     6
 * it under the terms of the GNU General Public License version 2 as
mathieu@9
     7
 * published by the Free Software Foundation;
mathieu@9
     8
 *
mathieu@9
     9
 * This program is distributed in the hope that it will be useful,
mathieu@9
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mathieu@9
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mathieu@9
    12
 * GNU General Public License for more details.
mathieu@9
    13
 *
mathieu@9
    14
 * You should have received a copy of the GNU General Public License
mathieu@9
    15
 * along with this program; if not, write to the Free Software
mathieu@9
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
mathieu@9
    17
 *
mathieu@9
    18
 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
mathieu@9
    19
 */
mathieu@9
    20
#include "buffer.h"
mathieu@286
    21
#include "ns3/assert.h"
craigdo@1504
    22
#include "ns3/log.h"
nbaldo@4708
    23
#include "ns3/fatal-error.h"
mathieu@9
    24
#include <iostream>
mathieu@1461
    25
craigdo@1504
    26
NS_LOG_COMPONENT_DEFINE ("Buffer");
mathieu@9
    27
tomh@3170
    28
#define LOG_INTERNAL_STATE(y)                                                                    \
tomh@3170
    29
NS_LOG_LOGIC (y << "start="<<m_start<<", end="<<m_end<<", zero start="<<m_zeroAreaStart<<              \
tomh@3170
    30
          ", zero end="<<m_zeroAreaEnd<<", count="<<m_data->m_count<<", size="<<m_data->m_size<<   \
tomh@3170
    31
          ", dirty start="<<m_data->m_dirtyStart<<", dirty end="<<m_data->m_dirtyEnd)
mathieu@1474
    32
mathieu@1491
    33
#ifdef BUFFER_HEURISTICS
mathieu@1491
    34
#define HEURISTICS(x) x
mathieu@1491
    35
#else
mathieu@1491
    36
#define HEURISTICS(x)
mathieu@1491
    37
#endif
mathieu@1491
    38
mathieu@1485
    39
//#define PRINT_STATS 1
mathieu@1474
    40
mathieu@16
    41
namespace ns3 {
mathieu@9
    42
mathieu@1491
    43
/**
mathieu@1491
    44
 * This data structure is variable-sized through its last member whose size
mathieu@1491
    45
 * is determined at allocation time and stored in the m_size field.
mathieu@1491
    46
 *
mathieu@1491
    47
 * The so-called "dirty area" describes the area in the buffer which
mathieu@1491
    48
 * has been reserved and used by a user. Multiple Buffer instances
mathieu@1491
    49
 * may reference the same BufferData object instance and may
mathieu@1491
    50
 * reference different parts of the underlying byte buffer. The
mathieu@1491
    51
 * "dirty area" is union of all the areas referenced by the Buffer
mathieu@1491
    52
 * instances which reference the same BufferData instance.
mathieu@1491
    53
 * New user data can be safely written only outside of the "dirty
mathieu@1491
    54
 * area" if the reference count is higher than 1 (that is, if
mathieu@1491
    55
 * more than one Buffer instance references the same BufferData).
mathieu@1491
    56
 */
mathieu@1474
    57
struct BufferData {
mathieu@1491
    58
  /* The reference count of an instance of this data structure.
mathieu@1491
    59
   * Each buffer which references an instance holds a count.
mathieu@1491
    60
   */
mathieu@1474
    61
  uint32_t m_count;
mathieu@1491
    62
  /* the size of the m_data field below.
mathieu@1491
    63
   */
mathieu@1474
    64
  uint32_t m_size;
tomh@3170
    65
  /* offset from the start of the m_data field below to the
tomh@3170
    66
   * start of the area in which user bytes were written.
tomh@3170
    67
   */
tomh@3170
    68
  uint32_t m_dirtyStart;
tomh@3170
    69
  /* offset from the start of the m_data field below to the
tomh@3170
    70
   * end of the area in which user bytes were written.
tomh@3170
    71
   */
tomh@3170
    72
  uint32_t m_dirtyEnd;
mathieu@1491
    73
  /* The real data buffer holds _at least_ one byte.
mathieu@1491
    74
   * Its real size is stored in the m_size field.
mathieu@1491
    75
   */
mathieu@1474
    76
  uint8_t m_data[1];
mathieu@1474
    77
};
mathieu@1474
    78
class BufferDataList : public std::vector<struct BufferData*>
mathieu@1474
    79
{
mathieu@1474
    80
public:
mathieu@1474
    81
  ~BufferDataList ();
mathieu@1474
    82
};
mathieu@9
    83
mathieu@1474
    84
static struct BufferData *BufferAllocate (uint32_t reqSize);
mathieu@1474
    85
mathieu@1474
    86
static void BufferDeallocate (struct BufferData *data);
mathieu@1474
    87
mathieu@1474
    88
mathieu@1474
    89
} // namespace ns3
mathieu@1474
    90
mathieu@1474
    91
namespace ns3 {
mathieu@1474
    92
mathieu@1491
    93
#ifdef BUFFER_HEURISTICS
mathieu@1474
    94
static uint32_t g_recommendedStart = 0;
mathieu@1485
    95
static uint64_t g_nAddNoRealloc = 0;
mathieu@1485
    96
static uint64_t g_nAddRealloc = 0;
mathieu@1474
    97
static BufferDataList  g_freeList;
mathieu@1485
    98
static uint32_t g_maxSize = 0;
mathieu@1485
    99
static uint64_t g_nAllocs = 0;
mathieu@1485
   100
static uint64_t g_nCreates = 0;
mathieu@1491
   101
#endif /* BUFFER_HEURISTICS */
mathieu@1474
   102
mathieu@1474
   103
BufferDataList::~BufferDataList ()
mathieu@957
   104
{
mathieu@1485
   105
#ifdef PRINT_STATS
mathieu@1491
   106
#ifdef BUFFER_HEURISTICS
mathieu@1485
   107
  double efficiency;
mathieu@1485
   108
  efficiency = g_nAllocs;
mathieu@1485
   109
  efficiency /= g_nCreates;
mathieu@1485
   110
  std::cout <<"buffer free list efficiency="<<efficiency<<" (lower is better)" << std::endl;
mathieu@1485
   111
  std::cout <<"buffer free list max size="<<g_maxSize<<std::endl;
mathieu@1485
   112
  std::cout <<"buffer free list recommended start="<<g_recommendedStart<<std::endl;
mathieu@1485
   113
  double addEfficiency;
mathieu@1485
   114
  addEfficiency = g_nAddRealloc;
mathieu@1485
   115
  addEfficiency /= g_nAddNoRealloc;
mathieu@1485
   116
  std::cout <<"buffer add efficiency=" << addEfficiency << " (lower is better)"<<std::endl;
mathieu@1485
   117
  //std::cout <<"n add reallocs="<< g_nAddRealloc << std::endl;
mathieu@1485
   118
  //std::cout <<"n add no reallocs="<< g_nAddNoRealloc << std::endl;
mathieu@1491
   119
#endif /* BUFFER_HEURISTICS */
mathieu@1485
   120
#endif /* PRINT_STATS */
mathieu@957
   121
  for (BufferDataList::iterator i = begin ();
mathieu@957
   122
       i != end (); i++)
mathieu@957
   123
    {
mathieu@1474
   124
      BufferDeallocate (*i);
mathieu@957
   125
    }
mathieu@957
   126
}
mathieu@957
   127
mathieu@1474
   128
struct BufferData *
mathieu@1474
   129
BufferAllocate (uint32_t reqSize)
mathieu@9
   130
{
mathieu@150
   131
  if (reqSize == 0) 
mathieu@150
   132
    {
mathieu@150
   133
      reqSize = 1;
mathieu@150
   134
    }
mathieu@286
   135
  NS_ASSERT (reqSize >= 1);
mathieu@1474
   136
  uint32_t size = reqSize - 1 + sizeof (struct BufferData);
mathieu@150
   137
  uint8_t *b = new uint8_t [size];
mathieu@1474
   138
  struct BufferData *data = reinterpret_cast<struct BufferData*>(b);
mathieu@150
   139
  data->m_size = reqSize;
mathieu@150
   140
  data->m_count = 1;
mathieu@150
   141
  return data;
mathieu@9
   142
}
mathieu@9
   143
mathieu@9
   144
void
mathieu@1474
   145
BufferDeallocate (struct BufferData *data)
mathieu@9
   146
{
mathieu@1474
   147
  NS_ASSERT (data->m_count == 0);
mathieu@150
   148
  uint8_t *buf = reinterpret_cast<uint8_t *> (data);
mathieu@150
   149
  delete [] buf;
mathieu@9
   150
}
mathieu@1491
   151
#ifdef BUFFER_HEURISTICS
mathieu@9
   152
void
mathieu@1474
   153
Buffer::Recycle (struct BufferData *data)
mathieu@9
   154
{
mathieu@286
   155
  NS_ASSERT (data->m_count == 0);
mathieu@1474
   156
  g_maxSize = std::max (g_maxSize, data->m_size);
mathieu@1474
   157
  /* feed into free list */
mathieu@1474
   158
  if (data->m_size < g_maxSize ||
mathieu@1474
   159
      g_freeList.size () > 1000)
mathieu@150
   160
    {
mathieu@1474
   161
      BufferDeallocate (data);
mathieu@150
   162
    }
mathieu@1485
   163
  else
mathieu@150
   164
    {
mathieu@1474
   165
      g_freeList.push_back (data);
mathieu@150
   166
    }
mathieu@9
   167
}
mathieu@9
   168
mathieu@1474
   169
BufferData *
mathieu@1474
   170
Buffer::Create (uint32_t dataSize)
mathieu@9
   171
{
mathieu@150
   172
  /* try to find a buffer correctly sized. */
mathieu@1485
   173
  g_nCreates++;
mathieu@1474
   174
  while (!g_freeList.empty ()) 
mathieu@150
   175
    {
mathieu@1474
   176
      struct BufferData *data = g_freeList.back ();
mathieu@1474
   177
      g_freeList.pop_back ();
mathieu@1474
   178
      if (data->m_size >= dataSize) 
mathieu@150
   179
        {
mathieu@150
   180
          data->m_count = 1;
mathieu@150
   181
          return data;
mathieu@150
   182
        }
mathieu@1474
   183
      BufferDeallocate (data);
mathieu@150
   184
    }
mathieu@1485
   185
  g_nAllocs++;
mathieu@1485
   186
  struct BufferData *data = BufferAllocate (dataSize);
mathieu@286
   187
  NS_ASSERT (data->m_count == 1);
mathieu@150
   188
  return data;
mathieu@9
   189
}
mathieu@9
   190
#else
mathieu@9
   191
void
mathieu@1474
   192
Buffer::Recycle (struct BufferData *data)
mathieu@9
   193
{
mathieu@1474
   194
  NS_ASSERT (data->m_count == 0);
mathieu@1474
   195
  BufferDeallocate (data);
mathieu@9
   196
}
mathieu@9
   197
mathieu@1474
   198
BufferData *
mathieu@1474
   199
Buffer::Create (uint32_t size)
mathieu@9
   200
{
mathieu@1474
   201
  return BufferAllocate (size);
mathieu@9
   202
}
mathieu@9
   203
#endif
mathieu@9
   204
mathieu@1461
   205
Buffer::Buffer ()
mathieu@1461
   206
{
mathieu@3160
   207
  NS_LOG_FUNCTION (this);
mathieu@1474
   208
  Initialize (0);
mathieu@1461
   209
}
mathieu@1461
   210
mathieu@1461
   211
Buffer::Buffer (uint32_t dataSize)
mathieu@1461
   212
{
mathieu@3160
   213
  NS_LOG_FUNCTION (this << dataSize);
mathieu@1474
   214
  Initialize (dataSize);
mathieu@1461
   215
}
mathieu@1461
   216
mathieu@1474
   217
bool
mathieu@1474
   218
Buffer::CheckInternalState (void) const
mathieu@1474
   219
{
mathieu@1474
   220
  bool offsetsOk = 
mathieu@1474
   221
    m_start <= m_zeroAreaStart &&
mathieu@1474
   222
    m_zeroAreaStart <= m_zeroAreaEnd &&
mathieu@1474
   223
    m_zeroAreaEnd <= m_end;
tomh@3170
   224
  bool dirtyOk =
tomh@3170
   225
    m_start >= m_data->m_dirtyStart &&
tomh@3170
   226
    m_end <= m_data->m_dirtyEnd;
mathieu@1474
   227
  bool internalSizeOk = m_end - (m_zeroAreaEnd - m_zeroAreaStart) <= m_data->m_size &&
mathieu@1474
   228
    m_start <= m_data->m_size &&
mathieu@1474
   229
    m_zeroAreaStart <= m_data->m_size;
mathieu@1474
   230
tomh@3170
   231
  bool ok = m_data->m_count > 0 && offsetsOk && dirtyOk && internalSizeOk;
mathieu@3160
   232
  if (!ok)
mathieu@3160
   233
    {
mathieu@3160
   234
      LOG_INTERNAL_STATE ("check " << this << 
mathieu@3160
   235
                          ", " << (offsetsOk?"true":"false") << 
tomh@3170
   236
                          ", " << (dirtyOk?"true":"false") << 
mathieu@3160
   237
                          ", " << (internalSizeOk?"true":"false") << " ");
mathieu@3160
   238
    }
mathieu@3160
   239
  return ok;
mathieu@1474
   240
}
mathieu@1474
   241
mathieu@1474
   242
void
mathieu@1474
   243
Buffer::Initialize (uint32_t zeroSize)
mathieu@1474
   244
{
mathieu@3158
   245
  NS_LOG_FUNCTION (this << zeroSize);
mathieu@1474
   246
  m_data = Buffer::Create (0);
mathieu@1491
   247
#ifdef BUFFER_HEURISTICS
mathieu@1474
   248
  m_start = std::min (m_data->m_size, g_recommendedStart);
mathieu@1491
   249
  m_maxZeroAreaStart = m_start;
mathieu@1491
   250
#else
mathieu@1491
   251
  m_start = 0;
mathieu@1491
   252
#endif /* BUFFER_HEURISTICS */
mathieu@1474
   253
  m_zeroAreaStart = m_start;
mathieu@1474
   254
  m_zeroAreaEnd = m_zeroAreaStart + zeroSize;
mathieu@1474
   255
  m_end = m_zeroAreaEnd;
tomh@3170
   256
  m_data->m_dirtyStart = m_start;
tomh@3170
   257
  m_data->m_dirtyEnd = m_end;
mathieu@1474
   258
  NS_ASSERT (CheckInternalState ());
mathieu@1474
   259
}
mathieu@1461
   260
mathieu@1461
   261
Buffer::Buffer (Buffer const&o)
mathieu@1461
   262
  : m_data (o.m_data),
mathieu@1491
   263
#ifdef BUFFER_HEURISTICS
mathieu@1474
   264
    m_maxZeroAreaStart (o.m_zeroAreaStart),
mathieu@1491
   265
#endif
mathieu@1473
   266
    m_zeroAreaStart (o.m_zeroAreaStart),
mathieu@1474
   267
    m_zeroAreaEnd (o.m_zeroAreaEnd),
mathieu@1461
   268
    m_start (o.m_start),
mathieu@1470
   269
    m_end (o.m_end)
mathieu@1461
   270
{
mathieu@3160
   271
  NS_LOG_FUNCTION (this << &o);
mathieu@1461
   272
  m_data->m_count++;
mathieu@1474
   273
  NS_ASSERT (CheckInternalState ());
mathieu@1461
   274
}
mathieu@1461
   275
mathieu@1461
   276
Buffer &
mathieu@1461
   277
Buffer::operator = (Buffer const&o)
mathieu@1461
   278
{
mathieu@3160
   279
  NS_LOG_FUNCTION (this << &o);
mathieu@1474
   280
  NS_ASSERT (CheckInternalState ());
mathieu@1461
   281
  if (m_data != o.m_data) 
mathieu@1461
   282
    {
mathieu@1461
   283
      // not assignment to self.
mathieu@1461
   284
      m_data->m_count--;
mathieu@1461
   285
      if (m_data->m_count == 0) 
mathieu@1461
   286
        {
mathieu@1461
   287
          Recycle (m_data);
mathieu@1461
   288
        }
mathieu@1461
   289
      m_data = o.m_data;
mathieu@1461
   290
      m_data->m_count++;
mathieu@1461
   291
    }
mathieu@1491
   292
  HEURISTICS (
mathieu@1474
   293
  g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart);
mathieu@1474
   294
  m_maxZeroAreaStart = o.m_maxZeroAreaStart;
mathieu@1491
   295
  );
mathieu@1473
   296
  m_zeroAreaStart = o.m_zeroAreaStart;
mathieu@1474
   297
  m_zeroAreaEnd = o.m_zeroAreaEnd;
mathieu@1461
   298
  m_start = o.m_start;
mathieu@1470
   299
  m_end = o.m_end;
mathieu@1474
   300
  NS_ASSERT (CheckInternalState ());
mathieu@1461
   301
  return *this;
mathieu@1461
   302
}
mathieu@1461
   303
mathieu@1461
   304
Buffer::~Buffer ()
mathieu@1461
   305
{
mathieu@3160
   306
  NS_LOG_FUNCTION (this);
mathieu@3160
   307
  NS_ASSERT (CheckInternalState ());
mathieu@1491
   308
  HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart));
mathieu@1461
   309
  m_data->m_count--;
mathieu@1461
   310
  if (m_data->m_count == 0) 
mathieu@1461
   311
    {
mathieu@1461
   312
      Recycle (m_data);
mathieu@1461
   313
    }
mathieu@1461
   314
}
mathieu@1461
   315
mathieu@1461
   316
uint32_t 
mathieu@1461
   317
Buffer::GetSize (void) const
mathieu@1461
   318
{
mathieu@1474
   319
  NS_ASSERT (CheckInternalState ());
mathieu@1474
   320
  return m_end - m_start;
mathieu@1461
   321
}
mathieu@1461
   322
mathieu@1461
   323
Buffer::Iterator 
mathieu@1461
   324
Buffer::Begin (void) const
mathieu@1461
   325
{
mathieu@1474
   326
  NS_ASSERT (CheckInternalState ());
mathieu@1463
   327
  return Buffer::Iterator (this);
mathieu@1461
   328
}
mathieu@1461
   329
Buffer::Iterator 
mathieu@1461
   330
Buffer::End (void) const
mathieu@1461
   331
{
mathieu@1474
   332
  NS_ASSERT (CheckInternalState ());
mathieu@1463
   333
  return Buffer::Iterator (this, false);
mathieu@1461
   334
}
mathieu@1461
   335
mathieu@1486
   336
uint32_t
mathieu@1486
   337
Buffer::GetInternalSize (void) const
mathieu@1486
   338
{
mathieu@1486
   339
  return m_zeroAreaStart - m_start + m_end - m_zeroAreaEnd;
mathieu@1486
   340
}
mathieu@1486
   341
uint32_t
mathieu@1486
   342
Buffer::GetInternalEnd (void) const
mathieu@1486
   343
{
mathieu@1486
   344
  return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
mathieu@1486
   345
}
mathieu@1486
   346
mathieu@3035
   347
bool
mathieu@1486
   348
Buffer::AddAtStart (uint32_t start)
mathieu@1486
   349
{
mathieu@3158
   350
  NS_LOG_FUNCTION (this << start);
mathieu@3035
   351
  bool dirty;
mathieu@1486
   352
  NS_ASSERT (CheckInternalState ());
tomh@3170
   353
  bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
mathieu@1486
   354
  if (m_start >= start && !isDirty)
mathieu@1486
   355
    {
mathieu@1486
   356
      /* enough space in the buffer and not dirty. 
mathieu@1486
   357
       * To add: |..|
mathieu@1486
   358
       * Before: |*****---------***|
mathieu@1486
   359
       * After:  |***..---------***|
mathieu@1486
   360
       */
tomh@3170
   361
      NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
mathieu@1486
   362
      m_start -= start;
tomh@3170
   363
      dirty = m_start > m_data->m_dirtyStart;
mathieu@3180
   364
      // update dirty area
mathieu@3180
   365
      m_data->m_dirtyStart = m_start;
mathieu@1491
   366
      HEURISTICS (g_nAddNoRealloc++);
mathieu@1486
   367
    } 
mathieu@1486
   368
  else
mathieu@1486
   369
    {
mathieu@1486
   370
      uint32_t newSize = GetInternalSize () + start;
mathieu@1486
   371
      struct BufferData *newData = Buffer::Create (newSize);
mathieu@1486
   372
      memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ());
mathieu@1486
   373
      m_data->m_count--;
mathieu@1486
   374
      if (m_data->m_count == 0)
mathieu@1486
   375
        {
mathieu@1486
   376
          Buffer::Recycle (m_data);
mathieu@1486
   377
        }
mathieu@1486
   378
      m_data = newData;
mathieu@1486
   379
mathieu@3035
   380
      int32_t delta = start - m_start;
mathieu@3030
   381
      m_start += delta;
mathieu@1486
   382
      m_zeroAreaStart += delta;
mathieu@1486
   383
      m_zeroAreaEnd += delta;
mathieu@1486
   384
      m_end += delta;
mathieu@3035
   385
      m_start -= start;
mathieu@1486
   386
mathieu@3180
   387
      // update dirty area
mathieu@3180
   388
      m_data->m_dirtyStart = m_start;
mathieu@3180
   389
      m_data->m_dirtyEnd = m_end;
mathieu@3180
   390
mathieu@3035
   391
      dirty = true;
mathieu@3030
   392
mathieu@1491
   393
      HEURISTICS (g_nAddRealloc++);
mathieu@1491
   394
    }
mathieu@1491
   395
  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
craigdo@1504
   396
  LOG_INTERNAL_STATE ("add start=" << start << ", ");
mathieu@1486
   397
  NS_ASSERT (CheckInternalState ());
mathieu@3035
   398
  return dirty;
mathieu@1486
   399
}
mathieu@3035
   400
bool
mathieu@1486
   401
Buffer::AddAtEnd (uint32_t end)
mathieu@1486
   402
{
mathieu@3158
   403
  NS_LOG_FUNCTION (this << end);
mathieu@3035
   404
  bool dirty;
mathieu@1486
   405
  NS_ASSERT (CheckInternalState ());
tomh@3170
   406
  bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
mathieu@1486
   407
  if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
mathieu@1486
   408
    {
mathieu@1486
   409
      /* enough space in buffer and not dirty
mathieu@1486
   410
       * Add:    |...|
mathieu@1486
   411
       * Before: |**----*****|
mathieu@1486
   412
       * After:  |**----...**|
mathieu@1486
   413
       */
tomh@3170
   414
      NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
mathieu@1486
   415
      m_end += end;
mathieu@3180
   416
      // update dirty area.
mathieu@3180
   417
      m_data->m_dirtyEnd = m_end;
mathieu@1486
   418
tomh@3170
   419
      dirty = m_end < m_data->m_dirtyEnd;
mathieu@3030
   420
mathieu@1491
   421
      HEURISTICS (g_nAddNoRealloc++);
mathieu@1486
   422
    } 
mathieu@1486
   423
  else
mathieu@1486
   424
    {
mathieu@1486
   425
      uint32_t newSize = GetInternalSize () + end;
mathieu@1486
   426
      struct BufferData *newData = Buffer::Create (newSize);
mathieu@1486
   427
      memcpy (newData->m_data, m_data->m_data + m_start, GetInternalSize ());
mathieu@1486
   428
      m_data->m_count--;
mathieu@1486
   429
      if (m_data->m_count == 0) 
mathieu@1486
   430
        {
mathieu@1486
   431
          Buffer::Recycle (m_data);
mathieu@1486
   432
        }
mathieu@1486
   433
      m_data = newData;
mathieu@1486
   434
mathieu@3035
   435
      int32_t delta = -m_start;
mathieu@3030
   436
      m_zeroAreaStart += delta;
mathieu@3030
   437
      m_zeroAreaEnd += delta;
mathieu@3030
   438
      m_end += delta;
mathieu@3031
   439
      m_start += delta;
mathieu@3035
   440
      m_end += end;
mathieu@1486
   441
mathieu@3180
   442
      // update dirty area
mathieu@3180
   443
      m_data->m_dirtyStart = m_start;
mathieu@3180
   444
      m_data->m_dirtyEnd = m_end;
mathieu@3180
   445
mathieu@3035
   446
      dirty = true;
mathieu@1486
   447
mathieu@1491
   448
      HEURISTICS (g_nAddRealloc++);
mathieu@1486
   449
    } 
mathieu@1491
   450
  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
craigdo@1504
   451
  LOG_INTERNAL_STATE ("add end=" << end << ", ");
mathieu@1486
   452
  NS_ASSERT (CheckInternalState ());
mathieu@3030
   453
mathieu@3035
   454
  return dirty;
mathieu@1486
   455
}
mathieu@1486
   456
mathieu@3035
   457
void
mathieu@2992
   458
Buffer::AddAtEnd (const Buffer &o)
mathieu@2992
   459
{
mathieu@3158
   460
  NS_LOG_FUNCTION (this << &o);
mathieu@3060
   461
  if (m_data->m_count == 1 &&
mathieu@3060
   462
      m_end == m_zeroAreaEnd &&
tomh@3170
   463
      m_end == m_data->m_dirtyEnd &&
mathieu@2993
   464
      o.m_start == o.m_zeroAreaStart &&
mathieu@2993
   465
      o.m_zeroAreaEnd - o.m_zeroAreaStart > 0)
mathieu@2993
   466
    {
mathieu@2993
   467
      /**
mathieu@2993
   468
       * This is an optimization which kicks in when
mathieu@2993
   469
       * we attempt to aggregate two buffers which contain
mathieu@2993
   470
       * adjacent zero areas.
mathieu@2993
   471
       */
mathieu@2993
   472
      uint32_t zeroSize = o.m_zeroAreaEnd - o.m_zeroAreaStart;
mathieu@2993
   473
      m_zeroAreaEnd += zeroSize;
mathieu@2993
   474
      m_end = m_zeroAreaEnd;
tomh@3170
   475
      m_data->m_dirtyEnd = m_zeroAreaEnd;
mathieu@2993
   476
      uint32_t endData = o.m_end - o.m_zeroAreaEnd;
mathieu@2993
   477
      AddAtEnd (endData);
mathieu@2993
   478
      Buffer::Iterator dst = End ();
mathieu@2993
   479
      dst.Prev (endData);
mathieu@2993
   480
      Buffer::Iterator src = o.End ();
mathieu@2993
   481
      src.Prev (endData);
mathieu@2993
   482
      dst.Write (src, o.End ());
mathieu@3158
   483
      NS_ASSERT (CheckInternalState ());
mathieu@3035
   484
      return;
mathieu@2993
   485
    }
mathieu@3060
   486
mathieu@2992
   487
  Buffer dst = CreateFullCopy ();
mathieu@2992
   488
  Buffer src = o.CreateFullCopy ();
mathieu@2992
   489
mathieu@2992
   490
  dst.AddAtEnd (src.GetSize ());
mathieu@2992
   491
  Buffer::Iterator destStart = dst.End ();
mathieu@2992
   492
  destStart.Prev (src.GetSize ());
mathieu@2992
   493
  destStart.Write (src.Begin (), src.End ());
mathieu@2992
   494
  *this = dst;
mathieu@3158
   495
  NS_ASSERT (CheckInternalState ());
mathieu@2992
   496
}
mathieu@2992
   497
mathieu@2992
   498
void 
mathieu@1486
   499
Buffer::RemoveAtStart (uint32_t start)
mathieu@1486
   500
{
mathieu@3158
   501
  NS_LOG_FUNCTION (this << start);
mathieu@1486
   502
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   503
  uint32_t newStart = m_start + start;
mathieu@1486
   504
  if (newStart <= m_zeroAreaStart)
mathieu@1486
   505
    {
mathieu@1486
   506
      /* only remove start of buffer 
mathieu@1486
   507
       */
mathieu@1486
   508
      m_start = newStart;
mathieu@1486
   509
    }
mathieu@1486
   510
  else if (newStart <= m_zeroAreaEnd)
mathieu@1486
   511
    {
mathieu@1486
   512
      /* remove start of buffer _and_ start of zero area
mathieu@1486
   513
       */
mathieu@1486
   514
      uint32_t delta = newStart - m_zeroAreaStart;
mathieu@1486
   515
      m_start = m_zeroAreaStart;
mathieu@1486
   516
      m_zeroAreaEnd -= delta;
mathieu@1486
   517
      m_end -= delta;
mathieu@1486
   518
    } 
mathieu@1486
   519
  else if (newStart <= m_end)
mathieu@1486
   520
    {
mathieu@1486
   521
      /* remove start of buffer, complete zero area, and part
mathieu@1486
   522
       * of end of buffer 
mathieu@1486
   523
       */
mathieu@1486
   524
      NS_ASSERT (m_end >= start);
mathieu@1486
   525
      uint32_t zeroSize = m_zeroAreaEnd - m_zeroAreaStart;
mathieu@1486
   526
      m_start = newStart - zeroSize;
mathieu@1486
   527
      m_end -= zeroSize;
mathieu@1486
   528
      m_zeroAreaStart = m_start;
mathieu@1486
   529
      m_zeroAreaEnd = m_start;
mathieu@1486
   530
    }
mathieu@1486
   531
  else 
mathieu@1486
   532
    {
mathieu@1486
   533
      /* remove all buffer */
mathieu@1486
   534
      m_end -= m_zeroAreaEnd - m_zeroAreaStart;
mathieu@1486
   535
      m_start = m_end;
mathieu@1486
   536
      m_zeroAreaEnd = m_end;
mathieu@1486
   537
      m_zeroAreaStart = m_end;
mathieu@1486
   538
    }
mathieu@1491
   539
  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
craigdo@1504
   540
  LOG_INTERNAL_STATE ("rem start=" << start << ", ");
mathieu@1486
   541
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   542
}
mathieu@1486
   543
void 
mathieu@1486
   544
Buffer::RemoveAtEnd (uint32_t end)
mathieu@1486
   545
{
mathieu@3158
   546
  NS_LOG_FUNCTION (this << end);
mathieu@1486
   547
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   548
  uint32_t newEnd = m_end - std::min (end, m_end - m_start);
mathieu@1486
   549
  if (newEnd > m_zeroAreaEnd)
mathieu@1486
   550
    {
mathieu@1486
   551
      /* remove part of end of buffer */
mathieu@1486
   552
      m_end = newEnd;
mathieu@1486
   553
    }
mathieu@1486
   554
  else if (newEnd > m_zeroAreaStart)
mathieu@1486
   555
    {
mathieu@1486
   556
      /* remove end of buffer, part of zero area */
mathieu@1486
   557
      m_end = newEnd;
mathieu@1486
   558
      m_zeroAreaEnd = newEnd;
mathieu@1486
   559
    }
mathieu@1486
   560
  else if (newEnd > m_start)
mathieu@1486
   561
    {
mathieu@1486
   562
      /* remove end of buffer, zero area, part of start of buffer */
mathieu@1486
   563
      m_end = newEnd;
mathieu@1486
   564
      m_zeroAreaEnd = newEnd;
mathieu@1486
   565
      m_zeroAreaStart = newEnd;
mathieu@1486
   566
    }
mathieu@1486
   567
  else
mathieu@1486
   568
    {
mathieu@1486
   569
      /* remove all buffer */
mathieu@1486
   570
      m_end = m_start;
mathieu@1486
   571
      m_zeroAreaEnd = m_start;
mathieu@1486
   572
      m_zeroAreaStart = m_start;
mathieu@1486
   573
    }
mathieu@1491
   574
  HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
craigdo@1504
   575
  LOG_INTERNAL_STATE ("rem end=" << end << ", ");
mathieu@1486
   576
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   577
}
mathieu@1486
   578
mathieu@1486
   579
Buffer 
mathieu@1486
   580
Buffer::CreateFragment (uint32_t start, uint32_t length) const
mathieu@1486
   581
{
mathieu@3158
   582
  NS_LOG_FUNCTION (this << start << length);
mathieu@1486
   583
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   584
  Buffer tmp = *this;
mathieu@1486
   585
  tmp.RemoveAtStart (start);
mathieu@1486
   586
  tmp.RemoveAtEnd (GetSize () - (start + length));
mathieu@1486
   587
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   588
  return tmp;
mathieu@1486
   589
}
mathieu@1486
   590
mathieu@1486
   591
Buffer 
mathieu@1486
   592
Buffer::CreateFullCopy (void) const
mathieu@1486
   593
{
mathieu@3158
   594
  NS_LOG_FUNCTION (this);
mathieu@1486
   595
  NS_ASSERT (CheckInternalState ());
mathieu@2991
   596
  if (m_zeroAreaEnd - m_zeroAreaStart != 0) 
mathieu@1486
   597
    {
mathieu@1486
   598
      Buffer tmp;
mathieu@1486
   599
      tmp.AddAtStart (m_zeroAreaEnd - m_zeroAreaStart);
mathieu@1486
   600
      tmp.Begin ().WriteU8 (0, m_zeroAreaEnd - m_zeroAreaStart);
mathieu@1486
   601
      uint32_t dataStart = m_zeroAreaStart - m_start;
mathieu@1486
   602
      tmp.AddAtStart (dataStart);
mathieu@1486
   603
      tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
mathieu@1486
   604
      uint32_t dataEnd = m_end - m_zeroAreaEnd;
mathieu@1486
   605
      tmp.AddAtEnd (dataEnd);
mathieu@1486
   606
      Buffer::Iterator i = tmp.End ();
mathieu@1486
   607
      i.Prev (dataEnd);
mathieu@1486
   608
      i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
mathieu@3158
   609
      NS_ASSERT (tmp.CheckInternalState ());
mathieu@1486
   610
      return tmp;
mathieu@1486
   611
    }
mathieu@1486
   612
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   613
  return *this;
mathieu@1486
   614
}
mathieu@1486
   615
mathieu@3035
   616
int32_t 
mathieu@3035
   617
Buffer::GetCurrentStartOffset (void) const
mathieu@3035
   618
{
mathieu@3035
   619
  return m_start;
mathieu@3035
   620
}
mathieu@3035
   621
int32_t 
mathieu@3035
   622
Buffer::GetCurrentEndOffset (void) const
mathieu@3035
   623
{
mathieu@3035
   624
  return m_end;
mathieu@3035
   625
}
mathieu@3035
   626
mathieu@3035
   627
mathieu@1486
   628
void
mathieu@1486
   629
Buffer::TransformIntoRealBuffer (void) const
mathieu@1486
   630
{
mathieu@1486
   631
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   632
  Buffer tmp = CreateFullCopy ();
mathieu@1486
   633
  *const_cast<Buffer *> (this) = tmp;
mathieu@1486
   634
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   635
}
mathieu@1486
   636
mathieu@1486
   637
mathieu@1486
   638
uint8_t const*
mathieu@1486
   639
Buffer::PeekData (void) const
mathieu@1486
   640
{
mathieu@1486
   641
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   642
  TransformIntoRealBuffer ();
mathieu@1486
   643
  NS_ASSERT (CheckInternalState ());
mathieu@1486
   644
  return m_data->m_data + m_start;
mathieu@1486
   645
}
mathieu@1486
   646
mathieu@4518
   647
void
mathieu@4518
   648
Buffer::CopyData(std::ostream *os, uint32_t size) const
mathieu@4518
   649
{
nbaldo@4708
   650
  if (size > 0)
mathieu@4518
   651
    {
nbaldo@4708
   652
      uint32_t tmpsize = std::min (m_zeroAreaStart-m_start, size);
nbaldo@4708
   653
      os->write((const char*)(m_data->m_data + m_start), tmpsize);
nbaldo@4708
   654
      if (size > tmpsize) 
nbaldo@4708
   655
        { 
nbaldo@4708
   656
          size -= m_zeroAreaStart-m_start;
nbaldo@4708
   657
          tmpsize = std::min (m_zeroAreaEnd - m_zeroAreaStart, size);
nbaldo@4708
   658
          char zero = 0;
nbaldo@4708
   659
          for (uint32_t i = 0; i < tmpsize; ++i)
nbaldo@4708
   660
            {
nbaldo@4708
   661
              os->write (&zero, 1);
nbaldo@4708
   662
            }
nbaldo@4708
   663
          if (size > tmpsize)
nbaldo@4708
   664
            {
nbaldo@4708
   665
              size -= tmpsize;
nbaldo@4708
   666
              tmpsize = std::min (m_end - m_zeroAreaEnd, size);
nbaldo@4708
   667
              os->write ((const char*)(m_data->m_data + m_zeroAreaStart), tmpsize); 
nbaldo@4708
   668
            }
mathieu@4518
   669
        }
mathieu@4518
   670
    }
mathieu@4518
   671
}
mathieu@4518
   672
mathieu@1486
   673
/******************************************************
mathieu@1486
   674
 *            The buffer iterator below.
mathieu@1486
   675
 ******************************************************/
mathieu@1486
   676
mathieu@1486
   677
mathieu@1461
   678
Buffer::Iterator::Iterator ()
mathieu@1461
   679
  : m_zeroStart (0),
mathieu@1461
   680
    m_zeroEnd (0),
mathieu@1465
   681
    m_dataStart (0),
mathieu@1461
   682
    m_dataEnd (0),
mathieu@1461
   683
    m_current (0),
mathieu@1461
   684
    m_data (0)
mathieu@1461
   685
{}
mathieu@1463
   686
Buffer::Iterator::Iterator (Buffer const*buffer)
mathieu@1463
   687
{
mathieu@1463
   688
  Construct (buffer);
mathieu@1463
   689
  m_current = m_dataStart;
mathieu@1463
   690
}
mathieu@1463
   691
Buffer::Iterator::Iterator (Buffer const*buffer, bool dummy)
mathieu@1463
   692
{
mathieu@1463
   693
  Construct (buffer);
mathieu@1463
   694
  m_current = m_dataEnd;
mathieu@1463
   695
}
mathieu@1463
   696
mathieu@1463
   697
void
mathieu@1463
   698
Buffer::Iterator::Construct (const Buffer *buffer)
mathieu@1463
   699
{
mathieu@1474
   700
  m_zeroStart = buffer->m_zeroAreaStart;
mathieu@1474
   701
  m_zeroEnd = buffer->m_zeroAreaEnd;
mathieu@1467
   702
  m_dataStart = buffer->m_start;
mathieu@1474
   703
  m_dataEnd = buffer->m_end;
mathieu@1467
   704
  m_data = buffer->m_data->m_data;
mathieu@1463
   705
}
mathieu@1461
   706
mathieu@1461
   707
void 
mathieu@1461
   708
Buffer::Iterator::Next (void)
mathieu@1461
   709
{
mathieu@1461
   710
  NS_ASSERT (m_current + 1 <= m_dataEnd);
mathieu@1461
   711
  m_current++;
mathieu@1461
   712
}
mathieu@1461
   713
void 
mathieu@1461
   714
Buffer::Iterator::Prev (void)
mathieu@1461
   715
{
mathieu@1461
   716
  NS_ASSERT (m_current >= 1);
mathieu@1461
   717
  m_current--;
mathieu@1461
   718
}
mathieu@1461
   719
void 
mathieu@1461
   720
Buffer::Iterator::Next (uint32_t delta)
mathieu@1461
   721
{
mathieu@1461
   722
  NS_ASSERT (m_current + delta <= m_dataEnd);
mathieu@1461
   723
  m_current += delta;
mathieu@1461
   724
}
mathieu@1461
   725
void 
mathieu@1461
   726
Buffer::Iterator::Prev (uint32_t delta)
mathieu@1461
   727
{
mathieu@1461
   728
  NS_ASSERT (m_current >= delta);
mathieu@1461
   729
  m_current -= delta;
mathieu@1461
   730
}
mathieu@1461
   731
uint32_t
mathieu@1461
   732
Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
mathieu@1461
   733
{
mathieu@1461
   734
  NS_ASSERT (m_data == o.m_data);
mathieu@1464
   735
  int32_t diff = m_current - o.m_current;
mathieu@1461
   736
  if (diff < 0)
mathieu@1461
   737
    {
mathieu@1461
   738
      return -diff;
mathieu@1461
   739
    }
mathieu@1461
   740
  else
mathieu@1461
   741
    {
mathieu@1461
   742
      return diff;
mathieu@1461
   743
    }
mathieu@1461
   744
}
mathieu@1461
   745
mathieu@1461
   746
bool 
mathieu@1461
   747
Buffer::Iterator::IsEnd (void) const
mathieu@1461
   748
{
mathieu@1461
   749
  return m_current == m_dataEnd;
mathieu@1461
   750
}
mathieu@1461
   751
bool 
mathieu@1461
   752
Buffer::Iterator::IsStart (void) const
mathieu@1461
   753
{
mathieu@1465
   754
  return m_current == m_dataStart;
mathieu@1461
   755
}
mathieu@1461
   756
mathieu@1488
   757
bool 
mathieu@1488
   758
Buffer::Iterator::CheckNoZero (uint32_t start, uint32_t end) const
mathieu@1488
   759
{
mathieu@1488
   760
  bool ok = true;
mathieu@1488
   761
  for (uint32_t i = start; i < end; i++)
mathieu@1488
   762
    {
mathieu@1488
   763
      if (!Check (i))
mathieu@1488
   764
        {
mathieu@1488
   765
          ok = false;
mathieu@1488
   766
        }
mathieu@1488
   767
    }
mathieu@1488
   768
  return ok;
mathieu@1488
   769
}
mathieu@1488
   770
bool 
mathieu@1488
   771
Buffer::Iterator::Check (uint32_t i) const
mathieu@1488
   772
{
mathieu@1488
   773
  return i >= m_dataStart && 
mathieu@1491
   774
    !(i >= m_zeroStart && i < m_zeroEnd) &&
mathieu@1488
   775
    i <= m_dataEnd;
mathieu@1488
   776
}
mathieu@1488
   777
mathieu@1488
   778
mathieu@1461
   779
void 
mathieu@1461
   780
Buffer::Iterator::Write (Iterator start, Iterator end)
mathieu@1461
   781
{
mathieu@1461
   782
  NS_ASSERT (start.m_data == end.m_data);
mathieu@1461
   783
  NS_ASSERT (start.m_current <= end.m_current);
mathieu@1461
   784
  NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
mathieu@1461
   785
  NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
tomh@3170
   786
  NS_ASSERT (m_data != start.m_data);
mathieu@1461
   787
  uint32_t size = end.m_current - start.m_current;
mathieu@1467
   788
  Iterator cur = start;
mathieu@1467
   789
  for (uint32_t i = 0; i < size; i++)
mathieu@1467
   790
    {
mathieu@1467
   791
      uint8_t data = cur.ReadU8 ();
mathieu@1467
   792
      WriteU8 (data);
mathieu@1467
   793
    }
mathieu@1461
   794
}
mathieu@1461
   795
mathieu@1461
   796
void 
mathieu@1461
   797
Buffer::Iterator::WriteU16 (uint16_t data)
mathieu@1461
   798
{
mathieu@1466
   799
  WriteU8 (data & 0xff);
mathieu@1466
   800
  data >>= 8;
mathieu@1466
   801
  WriteU8 (data & 0xff);
mathieu@1461
   802
}
mathieu@1461
   803
void 
mathieu@1461
   804
Buffer::Iterator::WriteU32 (uint32_t data)
mathieu@1461
   805
{
mathieu@1466
   806
  WriteU8 (data & 0xff);
mathieu@1466
   807
  data >>= 8;
mathieu@1466
   808
  WriteU8 (data & 0xff);
mathieu@1466
   809
  data >>= 8;
mathieu@1466
   810
  WriteU8 (data & 0xff);
mathieu@1466
   811
  data >>= 8;
mathieu@1466
   812
  WriteU8 (data & 0xff);
mathieu@1461
   813
}
mathieu@1461
   814
void 
mathieu@1461
   815
Buffer::Iterator::WriteU64 (uint64_t data)
mathieu@1461
   816
{
mathieu@1466
   817
  WriteU8 (data & 0xff);
mathieu@1466
   818
  data >>= 8;
mathieu@1466
   819
  WriteU8 (data & 0xff);
mathieu@1466
   820
  data >>= 8;
mathieu@1466
   821
  WriteU8 (data & 0xff);
mathieu@1466
   822
  data >>= 8;
mathieu@1466
   823
  WriteU8 (data & 0xff);
mathieu@1466
   824
  data >>= 8;
mathieu@1466
   825
  WriteU8 (data & 0xff);
mathieu@1466
   826
  data >>= 8;
mathieu@1466
   827
  WriteU8 (data & 0xff);
mathieu@1466
   828
  data >>= 8;
mathieu@1466
   829
  WriteU8 (data & 0xff);
mathieu@1466
   830
  data >>= 8;
mathieu@1466
   831
  WriteU8 (data & 0xff);
mathieu@1461
   832
}
mathieu@1461
   833
void 
mathieu@2792
   834
Buffer::Iterator::WriteHtolsbU16 (uint16_t data)
mathieu@2792
   835
{
mathieu@2792
   836
  WriteU8 ((data >> 0) & 0xff);
mathieu@2792
   837
  WriteU8 ((data >> 8) & 0xff);
mathieu@2792
   838
}
mathieu@2792
   839
void 
mathieu@2792
   840
Buffer::Iterator::WriteHtolsbU32 (uint32_t data)
mathieu@2792
   841
{
mathieu@2792
   842
  WriteU8 ((data >> 0) & 0xff);
mathieu@2792
   843
  WriteU8 ((data >> 8) & 0xff);
mathieu@2792
   844
  WriteU8 ((data >> 16) & 0xff);
mathieu@2792
   845
  WriteU8 ((data >> 24) & 0xff);
mathieu@2792
   846
}
mathieu@2792
   847
void 
mathieu@2792
   848
Buffer::Iterator::WriteHtolsbU64 (uint64_t data)
mathieu@2792
   849
{
mathieu@2792
   850
  WriteU8 ((data >> 0) & 0xff);
mathieu@2792
   851
  WriteU8 ((data >> 8) & 0xff);
mathieu@2792
   852
  WriteU8 ((data >> 16) & 0xff);
mathieu@2792
   853
  WriteU8 ((data >> 24) & 0xff);
mathieu@2792
   854
  WriteU8 ((data >> 32) & 0xff);
mathieu@2792
   855
  WriteU8 ((data >> 40) & 0xff);
mathieu@2792
   856
  WriteU8 ((data >> 48) & 0xff);
adrian@4442
   857
  WriteU8 ((data >> 56) & 0xff);
mathieu@2792
   858
}
mathieu@2792
   859
mathieu@2792
   860
void 
mathieu@1461
   861
Buffer::Iterator::WriteHtonU16 (uint16_t data)
mathieu@1461
   862
{
mathieu@1466
   863
  WriteU8 ((data >> 8) & 0xff);
mathieu@1466
   864
  WriteU8 ((data >> 0) & 0xff);
mathieu@1461
   865
}
mathieu@1461
   866
void 
mathieu@1461
   867
Buffer::Iterator::WriteHtonU32 (uint32_t data)
mathieu@1461
   868
{
mathieu@1466
   869
  WriteU8 ((data >> 24) & 0xff);
mathieu@1466
   870
  WriteU8 ((data >> 16) & 0xff);
mathieu@1466
   871
  WriteU8 ((data >> 8) & 0xff);
mathieu@1466
   872
  WriteU8 ((data >> 0) & 0xff);
mathieu@1461
   873
}
mathieu@1461
   874
void 
mathieu@1461
   875
Buffer::Iterator::WriteHtonU64 (uint64_t data)
mathieu@1461
   876
{
mathieu@1466
   877
  WriteU8 ((data >> 56) & 0xff);
mathieu@1466
   878
  WriteU8 ((data >> 48) & 0xff);
mathieu@1466
   879
  WriteU8 ((data >> 40) & 0xff);
mathieu@1466
   880
  WriteU8 ((data >> 32) & 0xff);
mathieu@1466
   881
  WriteU8 ((data >> 24) & 0xff);
mathieu@1466
   882
  WriteU8 ((data >> 16) & 0xff);
mathieu@1466
   883
  WriteU8 ((data >> 8) & 0xff);
mathieu@1466
   884
  WriteU8 ((data >> 0) & 0xff);
mathieu@1461
   885
}
mathieu@1461
   886
void 
mathieu@1461
   887
Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
mathieu@1461
   888
{
mathieu@1466
   889
  for (uint32_t i = 0; i < size; i++)
mathieu@1466
   890
    {
mathieu@1466
   891
      WriteU8 (buffer[i]);
mathieu@1466
   892
    }
mathieu@1461
   893
}
mathieu@1461
   894
mathieu@1461
   895
uint16_t 
mathieu@1461
   896
Buffer::Iterator::ReadU16 (void)
mathieu@1461
   897
{
mathieu@1466
   898
  uint8_t byte0 = ReadU8 ();
mathieu@1466
   899
  uint8_t byte1 = ReadU8 ();
mathieu@1466
   900
  uint16_t data = byte1;
mathieu@1466
   901
  data <<= 8;
mathieu@1466
   902
  data |= byte0;
mathieu@1466
   903
mathieu@1466
   904
  return data;
mathieu@1461
   905
}
mathieu@1461
   906
uint32_t 
mathieu@1461
   907
Buffer::Iterator::ReadU32 (void)
mathieu@1461
   908
{
mathieu@1466
   909
  uint8_t byte0 = ReadU8 ();
mathieu@1466
   910
  uint8_t byte1 = ReadU8 ();
mathieu@1466
   911
  uint8_t byte2 = ReadU8 ();
mathieu@1466
   912
  uint8_t byte3 = ReadU8 ();
mathieu@1466
   913
  uint32_t data = byte3;
mathieu@1466
   914
  data <<= 8;
mathieu@1466
   915
  data |= byte2;
mathieu@1466
   916
  data <<= 8;
mathieu@1466
   917
  data |= byte1;
mathieu@1466
   918
  data <<= 8;
mathieu@1466
   919
  data |= byte0;
mathieu@1466
   920
  return data;
mathieu@1461
   921
}
mathieu@1461
   922
uint64_t 
mathieu@1461
   923
Buffer::Iterator::ReadU64 (void)
mathieu@1461
   924
{
mathieu@1466
   925
  uint8_t byte0 = ReadU8 ();
mathieu@1466
   926
  uint8_t byte1 = ReadU8 ();
mathieu@1466
   927
  uint8_t byte2 = ReadU8 ();
mathieu@1466
   928
  uint8_t byte3 = ReadU8 ();
mathieu@1466
   929
  uint8_t byte4 = ReadU8 ();
mathieu@1466
   930
  uint8_t byte5 = ReadU8 ();
mathieu@1466
   931
  uint8_t byte6 = ReadU8 ();
mathieu@1466
   932
  uint8_t byte7 = ReadU8 ();
adrian@4442
   933
  uint64_t data = byte7;
mathieu@1466
   934
  data <<= 8;
mathieu@1466
   935
  data |= byte6;
mathieu@1466
   936
  data <<= 8;
mathieu@1466
   937
  data |= byte5;
mathieu@1466
   938
  data <<= 8;
mathieu@1466
   939
  data |= byte4;
mathieu@1466
   940
  data <<= 8;
mathieu@1466
   941
  data |= byte3;
mathieu@1466
   942
  data <<= 8;
mathieu@1466
   943
  data |= byte2;
mathieu@1466
   944
  data <<= 8;
mathieu@1466
   945
  data |= byte1;
mathieu@1466
   946
  data <<= 8;
mathieu@1466
   947
  data |= byte0;
mathieu@1466
   948
mathieu@1466
   949
  return data;
mathieu@1461
   950
}
mathieu@1461
   951
uint16_t 
mathieu@1461
   952
Buffer::Iterator::ReadNtohU16 (void)
mathieu@1461
   953
{
mathieu@1461
   954
  uint16_t retval = 0;
mathieu@1466
   955
  retval |= ReadU8 ();
mathieu@1466
   956
  retval <<= 8;
mathieu@1466
   957
  retval |= ReadU8 ();
mathieu@1461
   958
  return retval;
mathieu@1461
   959
}
mathieu@1461
   960
uint32_t 
mathieu@1461
   961
Buffer::Iterator::ReadNtohU32 (void)
mathieu@1461
   962
{
mathieu@1461
   963
  uint32_t retval = 0;
mathieu@1466
   964
  retval |= ReadU8 ();
mathieu@1466
   965
  retval <<= 8;
mathieu@1466
   966
  retval |= ReadU8 ();
mathieu@1466
   967
  retval <<= 8;
mathieu@1466
   968
  retval |= ReadU8 ();
mathieu@1466
   969
  retval <<= 8;
mathieu@1466
   970
  retval |= ReadU8 ();
mathieu@1461
   971
  return retval;
mathieu@1461
   972
}
mathieu@1461
   973
uint64_t 
mathieu@1461
   974
Buffer::Iterator::ReadNtohU64 (void)
mathieu@1461
   975
{
mathieu@1461
   976
  uint64_t retval = 0;
mathieu@1466
   977
  retval |= ReadU8 ();
mathieu@1466
   978
  retval <<= 8;
mathieu@1466
   979
  retval |= ReadU8 ();
mathieu@1466
   980
  retval <<= 8;
mathieu@1466
   981
  retval |= ReadU8 ();
mathieu@1466
   982
  retval <<= 8;
mathieu@1466
   983
  retval |= ReadU8 ();
mathieu@1466
   984
  retval <<= 8;
mathieu@1466
   985
  retval |= ReadU8 ();
mathieu@1466
   986
  retval <<= 8;
mathieu@1466
   987
  retval |= ReadU8 ();
mathieu@1466
   988
  retval <<= 8;
mathieu@1466
   989
  retval |= ReadU8 ();
mathieu@1466
   990
  retval <<= 8;
mathieu@1466
   991
  retval |= ReadU8 ();
mathieu@1461
   992
  return retval;
mathieu@1461
   993
}
mathieu@2792
   994
uint16_t 
mathieu@2792
   995
Buffer::Iterator::ReadLsbtohU16 (void)
mathieu@2792
   996
{
mathieu@2792
   997
  uint8_t byte0 = ReadU8 ();
mathieu@2792
   998
  uint8_t byte1 = ReadU8 ();
mathieu@2792
   999
  uint16_t data = byte1;
mathieu@2792
  1000
  data <<= 8;
mathieu@2792
  1001
  data |= byte0;
mathieu@2792
  1002
  return data;
mathieu@2792
  1003
}
mathieu@2792
  1004
uint32_t 
mathieu@2792
  1005
Buffer::Iterator::ReadLsbtohU32 (void)
mathieu@2792
  1006
{
mathieu@2792
  1007
  uint8_t byte0 = ReadU8 ();
mathieu@2792
  1008
  uint8_t byte1 = ReadU8 ();
mathieu@2792
  1009
  uint8_t byte2 = ReadU8 ();
mathieu@2792
  1010
  uint8_t byte3 = ReadU8 ();
mathieu@2792
  1011
  uint32_t data = byte3;
mathieu@2792
  1012
  data <<= 8;
mathieu@2792
  1013
  data |= byte2;
mathieu@2792
  1014
  data <<= 8;
mathieu@2792
  1015
  data |= byte1;
mathieu@2792
  1016
  data <<= 8;
mathieu@2792
  1017
  data |= byte0;
mathieu@2792
  1018
  return data;
mathieu@2792
  1019
}
mathieu@2792
  1020
uint64_t 
mathieu@2792
  1021
Buffer::Iterator::ReadLsbtohU64 (void)
mathieu@2792
  1022
{
mathieu@2792
  1023
  uint8_t byte0 = ReadU8 ();
mathieu@2792
  1024
  uint8_t byte1 = ReadU8 ();
mathieu@2792
  1025
  uint8_t byte2 = ReadU8 ();
mathieu@2792
  1026
  uint8_t byte3 = ReadU8 ();
mathieu@2792
  1027
  uint8_t byte4 = ReadU8 ();
mathieu@2792
  1028
  uint8_t byte5 = ReadU8 ();
mathieu@2792
  1029
  uint8_t byte6 = ReadU8 ();
mathieu@2792
  1030
  uint8_t byte7 = ReadU8 ();
adrian@4442
  1031
  uint64_t data = byte7;
mathieu@2792
  1032
  data <<= 8;
mathieu@2792
  1033
  data |= byte6;
mathieu@2792
  1034
  data <<= 8;
mathieu@2792
  1035
  data |= byte5;
mathieu@2792
  1036
  data <<= 8;
mathieu@2792
  1037
  data |= byte4;
mathieu@2792
  1038
  data <<= 8;
mathieu@2792
  1039
  data |= byte3;
mathieu@2792
  1040
  data <<= 8;
mathieu@2792
  1041
  data |= byte2;
mathieu@2792
  1042
  data <<= 8;
mathieu@2792
  1043
  data |= byte1;
mathieu@2792
  1044
  data <<= 8;
mathieu@2792
  1045
  data |= byte0;
mathieu@2792
  1046
mathieu@2792
  1047
  return data;
mathieu@2792
  1048
}
mathieu@1461
  1049
void 
mathieu@1466
  1050
Buffer::Iterator::Read (uint8_t *buffer, uint32_t size)
mathieu@1461
  1051
{
mathieu@1466
  1052
  for (uint32_t i = 0; i < size; i++)
mathieu@1466
  1053
    {
mathieu@1466
  1054
      buffer[i] = ReadU8 ();
mathieu@1466
  1055
    }
mathieu@1461
  1056
}
mathieu@1461
  1057
mathieu@1488
  1058
#ifndef BUFFER_USE_INLINE
mathieu@1488
  1059
mathieu@1488
  1060
void 
mathieu@1488
  1061
Buffer::Iterator::WriteU8  (uint8_t  data)
mathieu@1488
  1062
{
mathieu@1488
  1063
  if (m_current < m_dataStart)
mathieu@1488
  1064
    {
mathieu@1488
  1065
      // XXX trying to write outside of data area
mathieu@1488
  1066
      NS_ASSERT (false);
mathieu@1488
  1067
    }
mathieu@1488
  1068
  else if (m_current < m_zeroStart)
mathieu@1488
  1069
    {
mathieu@1488
  1070
      m_data[m_current] = data;
mathieu@1488
  1071
      m_current++;
mathieu@1488
  1072
    }
mathieu@1488
  1073
  else if (m_current < m_zeroEnd)
mathieu@1488
  1074
    {
mathieu@1488
  1075
      // XXX trying to write in zero area
mathieu@1488
  1076
      NS_ASSERT (false);
mathieu@1488
  1077
    }
mathieu@1488
  1078
  else if (m_current < m_dataEnd)
mathieu@1488
  1079
    {
mathieu@1488
  1080
      m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
mathieu@1488
  1081
      m_current++;      
mathieu@1488
  1082
    }
mathieu@1488
  1083
  else 
mathieu@1488
  1084
    {
mathieu@1488
  1085
      // XXX trying to write outside of data area
mathieu@1488
  1086
      NS_ASSERT (false);
mathieu@1488
  1087
    }
mathieu@1488
  1088
}
mathieu@1488
  1089
mathieu@1488
  1090
void 
mathieu@1488
  1091
Buffer::Iterator::WriteU8 (uint8_t  data, uint32_t len)
mathieu@1488
  1092
{
mathieu@1488
  1093
  for (uint32_t i = 0; i < len; i++)
mathieu@1488
  1094
    {
mathieu@1488
  1095
      WriteU8 (data);
mathieu@1488
  1096
    }
mathieu@1488
  1097
}
mathieu@1488
  1098
mathieu@1489
  1099
uint8_t  
mathieu@1489
  1100
Buffer::Iterator::ReadU8 (void)
mathieu@1489
  1101
{
mathieu@1489
  1102
  if (m_current < m_dataStart)
mathieu@1489
  1103
    {
mathieu@1489
  1104
      // XXX trying to read from outside of data area
mathieu@1489
  1105
      NS_ASSERT (false);
mathieu@1489
  1106
    }
mathieu@1489
  1107
  else if (m_current < m_zeroStart)
mathieu@1489
  1108
    {
mathieu@1489
  1109
      uint8_t data = m_data[m_current];
mathieu@1489
  1110
      m_current++;
mathieu@1489
  1111
      return data;
mathieu@1489
  1112
    }
mathieu@1489
  1113
  else if (m_current < m_zeroEnd)
mathieu@1489
  1114
    {
mathieu@1489
  1115
      m_current++;
mathieu@1489
  1116
      return 0;
mathieu@1489
  1117
    }
mathieu@1489
  1118
  else if (m_current < m_dataEnd)
mathieu@1489
  1119
    {
mathieu@1489
  1120
      uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
mathieu@1489
  1121
      m_current++;
mathieu@1489
  1122
      return data;
mathieu@1489
  1123
    }
mathieu@1489
  1124
  else 
mathieu@1489
  1125
    {
mathieu@1489
  1126
      // XXX trying to read from outside of data area
mathieu@1489
  1127
      NS_ASSERT (false);
mathieu@1489
  1128
    }
mathieu@1489
  1129
  // to quiet compiler.
mathieu@1489
  1130
  return 0;
mathieu@1489
  1131
}
mathieu@1489
  1132
mathieu@1488
  1133
#endif /* BUFFER_USE_INLINE */
mathieu@1488
  1134
vincent@3363
  1135
uint16_t
vincent@3363
  1136
Buffer::Iterator::CalculateIpChecksum(uint16_t size)
vincent@3363
  1137
{
vincent@3363
  1138
  return CalculateIpChecksum(size, 0);
vincent@3363
  1139
}
vincent@3363
  1140
vincent@3363
  1141
uint16_t
vincent@3363
  1142
Buffer::Iterator::CalculateIpChecksum(uint16_t size, uint32_t initialChecksum)
vincent@3363
  1143
{
vincent@3363
  1144
  /* see RFC 1071 to understand this code. */
vincent@3363
  1145
  uint32_t sum = initialChecksum;
vincent@3363
  1146
vincent@3363
  1147
  for (int j = 0; j < size/2; j++)
vincent@3363
  1148
    sum += ReadU16 ();
vincent@3363
  1149
vincent@3363
  1150
  if (size & 1)
vincent@3363
  1151
     sum += ReadU8 ();
vincent@3363
  1152
vincent@3363
  1153
  while (sum >> 16)
vincent@3363
  1154
    sum = (sum & 0xffff) + (sum >> 16);
vincent@3363
  1155
  return ~sum;
vincent@3363
  1156
}
vincent@3363
  1157
mathieu@3404
  1158
uint32_t 
mathieu@3404
  1159
Buffer::Iterator::GetSize (void) const
mathieu@3404
  1160
{
mathieu@3404
  1161
  return m_dataEnd - m_dataStart;
mathieu@3404
  1162
}
mathieu@3404
  1163
mathieu@1461
  1164
} // namespace ns3
mathieu@9
  1165
mathieu@9
  1166
mathieu@9
  1167
#ifdef RUN_SELF_TESTS
mathieu@9
  1168
mathieu@14
  1169
#include "ns3/test.h"
gjc@943
  1170
#include "ns3/random-variable.h"
mathieu@9
  1171
#include <iomanip>
mathieu@9
  1172
mathieu@1474
  1173
mathieu@16
  1174
namespace ns3 {
mathieu@9
  1175
mathieu@9
  1176
class BufferTest: public Test {
mathieu@9
  1177
private:
mathieu@150
  1178
  bool EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[]);
mathieu@9
  1179
public:
mathieu@150
  1180
  virtual bool RunTests (void);
mathieu@150
  1181
  BufferTest ();
mathieu@9
  1182
};
mathieu@9
  1183
mathieu@9
  1184
mathieu@9
  1185
BufferTest::BufferTest ()
mathieu@150
  1186
  : Test ("Buffer") {}
mathieu@9
  1187
mathieu@9
  1188
bool
mathieu@122
  1189
BufferTest::EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[])
mathieu@9
  1190
{
mathieu@150
  1191
  bool success = true;
mathieu@150
  1192
  uint8_t *expected = array;
mathieu@150
  1193
  uint8_t const*got;
mathieu@150
  1194
  got = b.PeekData ();
mathieu@150
  1195
  for (uint32_t j = 0; j < n; j++) 
mathieu@150
  1196
    {
mathieu@150
  1197
      if (got[j] != expected[j]) 
mathieu@150
  1198
        {
mathieu@150
  1199
          success = false;
mathieu@150
  1200
        }
mathieu@150
  1201
    }
mathieu@150
  1202
  if (!success) 
mathieu@150
  1203
    {
mathieu@150
  1204
      Failure () << "Buffer -- ";
mathieu@150
  1205
      Failure () << "expected: n=";
mathieu@150
  1206
      Failure () << n << ", ";
mathieu@150
  1207
      Failure ().setf (std::ios::hex, std::ios::basefield);
mathieu@150
  1208
      for (uint32_t j = 0; j < n; j++) 
mathieu@150
  1209
        {
mathieu@150
  1210
          Failure () << (uint16_t)expected[j] << " ";
mathieu@150
  1211
        }
mathieu@150
  1212
      Failure ().setf (std::ios::dec, std::ios::basefield);
mathieu@150
  1213
      Failure () << "got: ";
mathieu@150
  1214
      Failure ().setf (std::ios::hex, std::ios::basefield);
mathieu@150
  1215
      for (uint32_t j = 0; j < n; j++) 
mathieu@150
  1216
        {
mathieu@150
  1217
          Failure () << (uint16_t)got[j] << " ";
mathieu@150
  1218
        }
mathieu@150
  1219
      Failure () << std::endl;
mathieu@150
  1220
    }
mathieu@150
  1221
  return success;
mathieu@9
  1222
}
mathieu@9
  1223
mathieu@9
  1224
/* Note: works only when variadic macros are
mathieu@9
  1225
 * available which is the case for gcc.
mathieu@9
  1226
 * XXX
mathieu@9
  1227
 */
mathieu@134
  1228
#define ENSURE_WRITTEN_BYTES(buffer, n, ...)     \
mathieu@134
  1229
  {                                              \
mathieu@150
  1230
  uint8_t bytes[] = {__VA_ARGS__};             \
mathieu@150
  1231
  if (!EnsureWrittenBytes (buffer, n , bytes)) \
mathieu@150
  1232
    {                                          \
gjc@943
  1233
      result = false;                          \
mathieu@150
  1234
    }                                          \
mathieu@134
  1235
  }
mathieu@9
  1236
mathieu@9
  1237
bool
mathieu@122
  1238
BufferTest::RunTests (void)
mathieu@9
  1239
{
gjc@943
  1240
  bool result = true;
mathieu@150
  1241
  Buffer buffer;
mathieu@150
  1242
  Buffer::Iterator i;
mathieu@150
  1243
  buffer.AddAtStart (6);
mathieu@150
  1244
  i = buffer.Begin ();
mathieu@150
  1245
  i.WriteU8 (0x66);
mathieu@150
  1246
  ENSURE_WRITTEN_BYTES (buffer, 1, 0x66);
mathieu@150
  1247
  i = buffer.Begin ();
mathieu@150
  1248
  i.WriteU8 (0x67);
mathieu@150
  1249
  ENSURE_WRITTEN_BYTES (buffer, 1, 0x67);
mathieu@150
  1250
  i.WriteHtonU16 (0x6568);
mathieu@150
  1251
  i = buffer.Begin ();
mathieu@150
  1252
  ENSURE_WRITTEN_BYTES (buffer, 3, 0x67, 0x65, 0x68);
mathieu@150
  1253
  i.WriteHtonU16 (0x6369);
mathieu@150
  1254
  ENSURE_WRITTEN_BYTES (buffer, 3, 0x63, 0x69, 0x68);
mathieu@150
  1255
  i.WriteHtonU32 (0xdeadbeaf);
mathieu@150
  1256
  ENSURE_WRITTEN_BYTES (buffer, 6, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
mathieu@150
  1257
  buffer.AddAtStart (2);
mathieu@150
  1258
  i = buffer.Begin ();
mathieu@150
  1259
  i.WriteU16 (0);
mathieu@150
  1260
  ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
mathieu@150
  1261
  buffer.AddAtEnd (2);
mathieu@150
  1262
  i = buffer.Begin ();
mathieu@150
  1263
  i.Next (8);
mathieu@150
  1264
  i.WriteU16 (0);
mathieu@150
  1265
  ENSURE_WRITTEN_BYTES (buffer, 10, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
mathieu@150
  1266
  buffer.RemoveAtStart (3);
mathieu@150
  1267
  i = buffer.Begin ();
mathieu@150
  1268
  ENSURE_WRITTEN_BYTES (buffer, 7, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
mathieu@150
  1269
  buffer.RemoveAtEnd (4);
mathieu@150
  1270
  i = buffer.Begin ();
mathieu@150
  1271
  ENSURE_WRITTEN_BYTES (buffer, 3, 0x69, 0xde, 0xad);
mathieu@150
  1272
  buffer.AddAtStart (1);
mathieu@150
  1273
  i = buffer.Begin ();
mathieu@150
  1274
  i.WriteU8 (0xff);
mathieu@150
  1275
  ENSURE_WRITTEN_BYTES (buffer, 4, 0xff, 0x69, 0xde, 0xad);
mathieu@150
  1276
  buffer.AddAtEnd (1);
mathieu@150
  1277
  i = buffer.Begin ();
mathieu@150
  1278
  i.Next (4);
mathieu@150
  1279
  i.WriteU8 (0xff);
mathieu@150
  1280
  i.Prev (2);
mathieu@150
  1281
  uint16_t saved = i.ReadU16 ();
mathieu@150
  1282
  i.Prev (2);
mathieu@150
  1283
  i.WriteHtonU16 (0xff00);
mathieu@150
  1284
  i.Prev (2);
mathieu@150
  1285
  if (i.ReadNtohU16 () != 0xff00) 
mathieu@150
  1286
    {
gjc@943
  1287
      result = false;
mathieu@150
  1288
    }
mathieu@150
  1289
  i.Prev (2);
mathieu@150
  1290
  i.WriteU16 (saved);
mathieu@150
  1291
  ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
mathieu@150
  1292
  Buffer o = buffer;
mathieu@150
  1293
  ENSURE_WRITTEN_BYTES (o, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
mathieu@150
  1294
  o.AddAtStart (1);
mathieu@150
  1295
  i = o.Begin ();
mathieu@150
  1296
  i.WriteU8 (0xfe);
mathieu@150
  1297
  ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
mathieu@150
  1298
  buffer.AddAtStart (2);
mathieu@150
  1299
  i = buffer.Begin ();
mathieu@150
  1300
  i.WriteU8 (0xfd);
mathieu@150
  1301
  i.WriteU8 (0xfd);
mathieu@150
  1302
  ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
mathieu@150
  1303
  ENSURE_WRITTEN_BYTES (buffer, 7, 0xfd, 0xfd, 0xff, 0x69, 0xde, 0xad, 0xff);
mathieu@9
  1304
adrian@4442
  1305
  // test 64-bit read/write
adrian@4442
  1306
  Buffer buff64;
adrian@4442
  1307
  buff64.AddAtStart(8);
adrian@4442
  1308
  i = buff64.Begin();
adrian@4442
  1309
  i.WriteU64 (0x0123456789ABCDEFllu);
adrian@4442
  1310
  ENSURE_WRITTEN_BYTES (buff64, 8, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01);
adrian@4442
  1311
  i = buff64.Begin();
adrian@4442
  1312
  if (i.ReadLsbtohU64() != 0x0123456789abcdefllu)
adrian@4442
  1313
    {
adrian@4442
  1314
       result = false;
adrian@4442
  1315
    }
adrian@4442
  1316
  i = buff64.Begin();
adrian@4442
  1317
  i.WriteHtolsbU64 (0x0123456789ABCDEFllu);
adrian@4442
  1318
  ENSURE_WRITTEN_BYTES (buff64, 8, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01);
adrian@4442
  1319
  i = buff64.Begin();
adrian@4442
  1320
  if (i.ReadLsbtohU64() != 0x0123456789abcdefllu)
adrian@4442
  1321
    {
adrian@4442
  1322
       result = false;
adrian@4442
  1323
    }
adrian@4442
  1324
  i = buff64.Begin();
adrian@4442
  1325
  i.WriteHtonU64 (0x0123456789ABCDEFllu);
adrian@4442
  1326
  ENSURE_WRITTEN_BYTES (buff64, 8, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef);
adrian@4442
  1327
  i = buff64.Begin();
adrian@4442
  1328
  if (i.ReadNtohU64() != 0x0123456789abcdefllu)
adrian@4442
  1329
    {
adrian@4442
  1330
       result = false;
adrian@4442
  1331
    }
adrian@4442
  1332
mathieu@150
  1333
  // test self-assignment
mathieu@150
  1334
  {
mathieu@150
  1335
      Buffer a = o;
mathieu@150
  1336
      a = a;
mathieu@150
  1337
  }
mathieu@150
  1338
mathieu@150
  1339
  // test Remove start.
mathieu@150
  1340
  buffer = Buffer (5);
mathieu@150
  1341
  ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
mathieu@150
  1342
  buffer.RemoveAtStart (1);
mathieu@150
  1343
  ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
mathieu@150
  1344
  buffer.AddAtStart (1);
mathieu@150
  1345
  buffer.Begin ().WriteU8 (0xff);
mathieu@150
  1346
  ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0, 0, 0, 0);
mathieu@150
  1347
  buffer.RemoveAtStart(3);
mathieu@150
  1348
  ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
mathieu@150
  1349
  buffer.AddAtStart (4);
mathieu@150
  1350
  buffer.Begin ().WriteHtonU32 (0xdeadbeaf);
mathieu@150
  1351
  ENSURE_WRITTEN_BYTES (buffer, 6,  0xde, 0xad, 0xbe, 0xaf, 0, 0);
mathieu@150
  1352
  buffer.RemoveAtStart (2);
mathieu@150
  1353
  ENSURE_WRITTEN_BYTES (buffer, 4,  0xbe, 0xaf, 0, 0);
mathieu@150
  1354
  buffer.AddAtEnd (4);
mathieu@150
  1355
  i = buffer.Begin ();
mathieu@150
  1356
  i.Next (4);
mathieu@150
  1357
  i.WriteHtonU32 (0xdeadbeaf);
mathieu@150
  1358
  ENSURE_WRITTEN_BYTES (buffer, 8,  0xbe, 0xaf, 0, 0, 0xde, 0xad, 0xbe, 0xaf);
mathieu@150
  1359
  buffer.RemoveAtStart (5);
mathieu@150
  1360
  ENSURE_WRITTEN_BYTES (buffer, 3,  0xad, 0xbe, 0xaf);
mathieu@150
  1361
  // test Remove end
mathieu@150
  1362
  buffer = Buffer (5);
mathieu@150
  1363
  ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
mathieu@150
  1364
  buffer.RemoveAtEnd (1);
mathieu@150
  1365
  ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
mathieu@150
  1366
  buffer.AddAtEnd (2);
mathieu@150
  1367
  i = buffer.Begin ();
mathieu@150
  1368
  i.Next (4);
mathieu@150
  1369
  i.WriteU8 (0xab);
mathieu@150
  1370
  i.WriteU8 (0xac);
mathieu@150
  1371
  ENSURE_WRITTEN_BYTES (buffer, 6, 0, 0, 0, 0, 0xab, 0xac);
mathieu@150
  1372
  buffer.RemoveAtEnd (1);
mathieu@150
  1373
  ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0xab);
mathieu@150
  1374
  buffer.RemoveAtEnd (3);
mathieu@150
  1375
  ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
mathieu@150
  1376
  buffer.AddAtEnd (6);
mathieu@150
  1377
  i = buffer.Begin ();
mathieu@150
  1378
  i.Next (2);
mathieu@150
  1379
  i.WriteU8 (0xac);
mathieu@150
  1380
  i.WriteU8 (0xad);
mathieu@150
  1381
  i.WriteU8 (0xae);
mathieu@150
  1382
  i.WriteU8 (0xaf);
mathieu@150
  1383
  i.WriteU8 (0xba);
mathieu@150
  1384
  i.WriteU8 (0xbb);
mathieu@150
  1385
  ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
mathieu@150
  1386
  buffer.AddAtStart (3);
mathieu@150
  1387
  i = buffer.Begin ();
mathieu@150
  1388
  i.WriteU8 (0x30);
mathieu@150
  1389
  i.WriteU8 (0x31);
mathieu@150
  1390
  i.WriteU8 (0x32);
mathieu@150
  1391
  ENSURE_WRITTEN_BYTES (buffer, 11, 0x30, 0x31, 0x32, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
mathieu@150
  1392
  buffer.RemoveAtEnd (9);
mathieu@150
  1393
  ENSURE_WRITTEN_BYTES (buffer, 2, 0x30, 0x31);
mathieu@150
  1394
  buffer = Buffer (3);
mathieu@150
  1395
  buffer.AddAtEnd (2);
mathieu@150
  1396
  i = buffer.Begin ();
mathieu@150
  1397
  i.Next (3);
mathieu@150
  1398
  i.WriteHtonU16 (0xabcd);
mathieu@150
  1399
  buffer.AddAtStart (1);
mathieu@150
  1400
  buffer.Begin ().WriteU8 (0x21);
mathieu@150
  1401
  ENSURE_WRITTEN_BYTES (buffer, 6, 0x21, 0, 0, 0, 0xab, 0xcd);
mathieu@150
  1402
  buffer.RemoveAtEnd (8);
mathieu@150
  1403
  if (buffer.GetSize () != 0) 
mathieu@54
  1404
    {
gjc@943
  1405
      result = false;
mathieu@54
  1406
    }
mathieu@436
  1407
mathieu@436
  1408
  buffer = Buffer (6);
mathieu@436
  1409
  buffer.AddAtStart (9);
mathieu@436
  1410
  buffer.AddAtEnd (3);
mathieu@436
  1411
  i = buffer.End ();
mathieu@436
  1412
  i.Prev (1);
mathieu@436
  1413
  i.WriteU8 (1, 1);
mathieu@9
  1414
mathieu@780
  1415
  buffer = Buffer (6);
mathieu@780
  1416
  buffer.AddAtStart (3);
mathieu@780
  1417
  buffer.RemoveAtEnd (8);
mathieu@780
  1418
  buffer.AddAtEnd (4);
mathieu@780
  1419
  i = buffer.End ();
mathieu@780
  1420
  i.Prev (4);
mathieu@780
  1421
  i.WriteU8 (1, 4);
mathieu@780
  1422
mathieu@898
  1423
  buffer = Buffer (1);
mathieu@898
  1424
  buffer.AddAtEnd (100);
mathieu@898
  1425
  i = buffer.End ();
mathieu@898
  1426
  i.Prev (100);
mathieu@898
  1427
  i.WriteU8 (1, 100);
mathieu@898
  1428
mathieu@1471
  1429
#if 0
mathieu@1468
  1430
  buffer = Buffer (10);  
mathieu@1469
  1431
  ENSURE_WRITTEN_BYTES (buffer, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mathieu@1468
  1432
  buffer.Begin ().WriteU8 (1);
mathieu@1468
  1433
  ENSURE_WRITTEN_BYTES (buffer, 10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mathieu@1471
  1434
#endif
mathieu@1468
  1435
gjc@943
  1436
  // Bug #54
gjc@943
  1437
  {
gjc@943
  1438
    const uint32_t actualSize = 72602;
gjc@943
  1439
    const uint32_t chunkSize = 67624;
gjc@943
  1440
    UniformVariable bytesRng (0, 256);
gjc@943
  1441
gjc@943
  1442
    Buffer inputBuffer;
gjc@943
  1443
    Buffer outputBuffer;
gjc@943
  1444
    
gjc@943
  1445
    inputBuffer.AddAtEnd (actualSize);
gjc@943
  1446
    {
gjc@943
  1447
      Buffer::Iterator iter = inputBuffer.Begin ();
gjc@943
  1448
      for (uint32_t i = 0; i < actualSize; i++)
gjc@943
  1449
        iter.WriteU8 (static_cast<uint8_t> (bytesRng.GetValue ()));
gjc@943
  1450
    }
gjc@943
  1451
gjc@943
  1452
    outputBuffer.AddAtEnd (chunkSize);
gjc@943
  1453
    Buffer::Iterator iter = outputBuffer.End ();
gjc@943
  1454
    iter.Prev (chunkSize);
gjc@943
  1455
    iter.Write (inputBuffer.PeekData (), chunkSize);
gjc@943
  1456
gjc@943
  1457
    NS_TEST_ASSERT (memcmp (inputBuffer.PeekData (), outputBuffer.PeekData (), chunkSize) == 0);
gjc@943
  1458
  }
gjc@943
  1459
mathieu@2993
  1460
  buffer = Buffer (5);
mathieu@2993
  1461
  buffer.AddAtEnd (2);
mathieu@2993
  1462
  i = buffer.End ();
mathieu@2993
  1463
  i.Prev (2);
mathieu@2993
  1464
  i.WriteU8 (0);
mathieu@2993
  1465
  i.WriteU8 (0x66);
mathieu@2993
  1466
  ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
mathieu@2993
  1467
  Buffer frag0 = buffer.CreateFragment (0, 2);
mathieu@2993
  1468
  ENSURE_WRITTEN_BYTES (frag0, 2, 0x00, 0x00);
mathieu@2993
  1469
  Buffer frag1 = buffer.CreateFragment (2, 5);
mathieu@2993
  1470
  ENSURE_WRITTEN_BYTES (frag1, 5, 0x00, 0x00, 0x00, 0x00, 0x66);
mathieu@2993
  1471
  frag0.AddAtEnd (frag1);
mathieu@2993
  1472
  ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
mathieu@2993
  1473
  ENSURE_WRITTEN_BYTES (frag0, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
mathieu@2993
  1474
gjc@943
  1475
  return result;
mathieu@9
  1476
}
mathieu@9
  1477
mathieu@9
  1478
mathieu@9
  1479
mathieu@53
  1480
static BufferTest gBufferTest;
mathieu@9
  1481
mathieu@1461
  1482
} // namespace ns3
mathieu@9
  1483
mathieu@9
  1484
#endif /* RUN_SELF_TESTS */
mathieu@9
  1485
mathieu@9
  1486