00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "buffer.h"
00021 #include "ns3/assert.h"
00022 #include "ns3/log.h"
00023 #include <iostream>
00024
00025 NS_LOG_COMPONENT_DEFINE ("Buffer");
00026
00027 #define LOG_INTERNAL_STATE(y) \
00028 NS_LOG_LOGIC (y << "start="<<m_start<<", end="<<m_end<<", zero start="<<m_zeroAreaStart<< \
00029 ", zero end="<<m_zeroAreaEnd<<", count="<<m_data->m_count<<", size="<<m_data->m_size<< \
00030 ", dirty start="<<m_data->m_dirtyStart<<", dirty end="<<m_data->m_dirtyEnd)
00031
00032 #ifdef BUFFER_HEURISTICS
00033 #define HEURISTICS(x) x
00034 #else
00035 #define HEURISTICS(x)
00036 #endif
00037
00038
00039
00040 namespace ns3 {
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 struct BufferData {
00057
00058
00059
00060 uint32_t m_count;
00061
00062
00063 uint32_t m_size;
00064
00065
00066
00067 uint32_t m_dirtyStart;
00068
00069
00070
00071 uint32_t m_dirtyEnd;
00072
00073
00074
00075 uint8_t m_data[1];
00076 };
00077 class BufferDataList : public std::vector<struct BufferData*>
00078 {
00079 public:
00080 ~BufferDataList ();
00081 };
00082
00083 static struct BufferData *BufferAllocate (uint32_t reqSize);
00084
00085 static void BufferDeallocate (struct BufferData *data);
00086
00087
00088 }
00089
00090 namespace ns3 {
00091
00092 #ifdef BUFFER_HEURISTICS
00093 static uint32_t g_recommendedStart = 0;
00094 static uint64_t g_nAddNoRealloc = 0;
00095 static uint64_t g_nAddRealloc = 0;
00096 static BufferDataList g_freeList;
00097 static uint32_t g_maxSize = 0;
00098 static uint64_t g_nAllocs = 0;
00099 static uint64_t g_nCreates = 0;
00100 #endif
00101
00102 BufferDataList::~BufferDataList ()
00103 {
00104 #ifdef PRINT_STATS
00105 #ifdef BUFFER_HEURISTICS
00106 double efficiency;
00107 efficiency = g_nAllocs;
00108 efficiency /= g_nCreates;
00109 std::cout <<"buffer free list efficiency="<<efficiency<<" (lower is better)" << std::endl;
00110 std::cout <<"buffer free list max size="<<g_maxSize<<std::endl;
00111 std::cout <<"buffer free list recommended start="<<g_recommendedStart<<std::endl;
00112 double addEfficiency;
00113 addEfficiency = g_nAddRealloc;
00114 addEfficiency /= g_nAddNoRealloc;
00115 std::cout <<"buffer add efficiency=" << addEfficiency << " (lower is better)"<<std::endl;
00116
00117
00118 #endif
00119 #endif
00120 for (BufferDataList::iterator i = begin ();
00121 i != end (); i++)
00122 {
00123 BufferDeallocate (*i);
00124 }
00125 }
00126
00127 struct BufferData *
00128 BufferAllocate (uint32_t reqSize)
00129 {
00130 if (reqSize == 0)
00131 {
00132 reqSize = 1;
00133 }
00134 NS_ASSERT (reqSize >= 1);
00135 uint32_t size = reqSize - 1 + sizeof (struct BufferData);
00136 uint8_t *b = new uint8_t [size];
00137 struct BufferData *data = reinterpret_cast<struct BufferData*>(b);
00138 data->m_size = reqSize;
00139 data->m_count = 1;
00140 return data;
00141 }
00142
00143 void
00144 BufferDeallocate (struct BufferData *data)
00145 {
00146 NS_ASSERT (data->m_count == 0);
00147 uint8_t *buf = reinterpret_cast<uint8_t *> (data);
00148 delete [] buf;
00149 }
00150 #ifdef BUFFER_HEURISTICS
00151 void
00152 Buffer::Recycle (struct BufferData *data)
00153 {
00154 NS_ASSERT (data->m_count == 0);
00155 g_maxSize = std::max (g_maxSize, data->m_size);
00156
00157 if (data->m_size < g_maxSize ||
00158 g_freeList.size () > 1000)
00159 {
00160 BufferDeallocate (data);
00161 }
00162 else
00163 {
00164 g_freeList.push_back (data);
00165 }
00166 }
00167
00168 BufferData *
00169 Buffer::Create (uint32_t dataSize)
00170 {
00171
00172 g_nCreates++;
00173 while (!g_freeList.empty ())
00174 {
00175 struct BufferData *data = g_freeList.back ();
00176 g_freeList.pop_back ();
00177 if (data->m_size >= dataSize)
00178 {
00179 data->m_count = 1;
00180 return data;
00181 }
00182 BufferDeallocate (data);
00183 }
00184 g_nAllocs++;
00185 struct BufferData *data = BufferAllocate (dataSize);
00186 NS_ASSERT (data->m_count == 1);
00187 return data;
00188 }
00189 #else
00190 void
00191 Buffer::Recycle (struct BufferData *data)
00192 {
00193 NS_ASSERT (data->m_count == 0);
00194 BufferDeallocate (data);
00195 }
00196
00197 BufferData *
00198 Buffer::Create (uint32_t size)
00199 {
00200 return BufferAllocate (size);
00201 }
00202 #endif
00203
00204 Buffer::Buffer ()
00205 {
00206 NS_LOG_FUNCTION (this);
00207 Initialize (0);
00208 }
00209
00210 Buffer::Buffer (uint32_t dataSize)
00211 {
00212 NS_LOG_FUNCTION (this << dataSize);
00213 Initialize (dataSize);
00214 }
00215
00216 bool
00217 Buffer::CheckInternalState (void) const
00218 {
00219 bool offsetsOk =
00220 m_start <= m_zeroAreaStart &&
00221 m_zeroAreaStart <= m_zeroAreaEnd &&
00222 m_zeroAreaEnd <= m_end;
00223 bool dirtyOk =
00224 m_start >= m_data->m_dirtyStart &&
00225 m_end <= m_data->m_dirtyEnd;
00226 bool internalSizeOk = m_end - (m_zeroAreaEnd - m_zeroAreaStart) <= m_data->m_size &&
00227 m_start <= m_data->m_size &&
00228 m_zeroAreaStart <= m_data->m_size;
00229
00230 bool ok = m_data->m_count > 0 && offsetsOk && dirtyOk && internalSizeOk;
00231 if (!ok)
00232 {
00233 LOG_INTERNAL_STATE ("check " << this <<
00234 ", " << (offsetsOk?"true":"false") <<
00235 ", " << (dirtyOk?"true":"false") <<
00236 ", " << (internalSizeOk?"true":"false") << " ");
00237 }
00238 return ok;
00239 }
00240
00241 void
00242 Buffer::Initialize (uint32_t zeroSize)
00243 {
00244 NS_LOG_FUNCTION (this << zeroSize);
00245 m_data = Buffer::Create (0);
00246 #ifdef BUFFER_HEURISTICS
00247 m_start = std::min (m_data->m_size, g_recommendedStart);
00248 m_maxZeroAreaStart = m_start;
00249 #else
00250 m_start = 0;
00251 #endif
00252 m_zeroAreaStart = m_start;
00253 m_zeroAreaEnd = m_zeroAreaStart + zeroSize;
00254 m_end = m_zeroAreaEnd;
00255 m_data->m_dirtyStart = m_start;
00256 m_data->m_dirtyEnd = m_end;
00257 NS_ASSERT (CheckInternalState ());
00258 }
00259
00260 Buffer::Buffer (Buffer const&o)
00261 : m_data (o.m_data),
00262 #ifdef BUFFER_HEURISTICS
00263 m_maxZeroAreaStart (o.m_zeroAreaStart),
00264 #endif
00265 m_zeroAreaStart (o.m_zeroAreaStart),
00266 m_zeroAreaEnd (o.m_zeroAreaEnd),
00267 m_start (o.m_start),
00268 m_end (o.m_end)
00269 {
00270 NS_LOG_FUNCTION (this << &o);
00271 m_data->m_count++;
00272 NS_ASSERT (CheckInternalState ());
00273 }
00274
00275 Buffer &
00276 Buffer::operator = (Buffer const&o)
00277 {
00278 NS_LOG_FUNCTION (this << &o);
00279 NS_ASSERT (CheckInternalState ());
00280 if (m_data != o.m_data)
00281 {
00282
00283 m_data->m_count--;
00284 if (m_data->m_count == 0)
00285 {
00286 Recycle (m_data);
00287 }
00288 m_data = o.m_data;
00289 m_data->m_count++;
00290 }
00291 HEURISTICS (
00292 g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart);
00293 m_maxZeroAreaStart = o.m_maxZeroAreaStart;
00294 );
00295 m_zeroAreaStart = o.m_zeroAreaStart;
00296 m_zeroAreaEnd = o.m_zeroAreaEnd;
00297 m_start = o.m_start;
00298 m_end = o.m_end;
00299 NS_ASSERT (CheckInternalState ());
00300 return *this;
00301 }
00302
00303 Buffer::~Buffer ()
00304 {
00305 NS_LOG_FUNCTION (this);
00306 NS_ASSERT (CheckInternalState ());
00307 HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart));
00308 m_data->m_count--;
00309 if (m_data->m_count == 0)
00310 {
00311 Recycle (m_data);
00312 }
00313 }
00314
00315 uint32_t
00316 Buffer::GetSize (void) const
00317 {
00318 NS_ASSERT (CheckInternalState ());
00319 return m_end - m_start;
00320 }
00321
00322 Buffer::Iterator
00323 Buffer::Begin (void) const
00324 {
00325 NS_ASSERT (CheckInternalState ());
00326 return Buffer::Iterator (this);
00327 }
00328 Buffer::Iterator
00329 Buffer::End (void) const
00330 {
00331 NS_ASSERT (CheckInternalState ());
00332 return Buffer::Iterator (this, false);
00333 }
00334
00335 uint32_t
00336 Buffer::GetInternalSize (void) const
00337 {
00338 return m_zeroAreaStart - m_start + m_end - m_zeroAreaEnd;
00339 }
00340 uint32_t
00341 Buffer::GetInternalEnd (void) const
00342 {
00343 return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
00344 }
00345
00346 bool
00347 Buffer::AddAtStart (uint32_t start)
00348 {
00349 NS_LOG_FUNCTION (this << start);
00350 bool dirty;
00351 NS_ASSERT (CheckInternalState ());
00352 bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
00353 if (m_start >= start && !isDirty)
00354 {
00355
00356
00357
00358
00359
00360 NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
00361 m_start -= start;
00362 dirty = m_start > m_data->m_dirtyStart;
00363
00364 m_data->m_dirtyStart = m_start;
00365 HEURISTICS (g_nAddNoRealloc++);
00366 }
00367 else
00368 {
00369 uint32_t newSize = GetInternalSize () + start;
00370 struct BufferData *newData = Buffer::Create (newSize);
00371 memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ());
00372 m_data->m_count--;
00373 if (m_data->m_count == 0)
00374 {
00375 Buffer::Recycle (m_data);
00376 }
00377 m_data = newData;
00378
00379 int32_t delta = start - m_start;
00380 m_start += delta;
00381 m_zeroAreaStart += delta;
00382 m_zeroAreaEnd += delta;
00383 m_end += delta;
00384 m_start -= start;
00385
00386
00387 m_data->m_dirtyStart = m_start;
00388 m_data->m_dirtyEnd = m_end;
00389
00390 dirty = true;
00391
00392 HEURISTICS (g_nAddRealloc++);
00393 }
00394 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
00395 LOG_INTERNAL_STATE ("add start=" << start << ", ");
00396 NS_ASSERT (CheckInternalState ());
00397 return dirty;
00398 }
00399 bool
00400 Buffer::AddAtEnd (uint32_t end)
00401 {
00402 NS_LOG_FUNCTION (this << end);
00403 bool dirty;
00404 NS_ASSERT (CheckInternalState ());
00405 bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
00406 if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
00407 {
00408
00409
00410
00411
00412
00413 NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
00414 m_end += end;
00415
00416 m_data->m_dirtyEnd = m_end;
00417
00418 dirty = m_end < m_data->m_dirtyEnd;
00419
00420 HEURISTICS (g_nAddNoRealloc++);
00421 }
00422 else
00423 {
00424 uint32_t newSize = GetInternalSize () + end;
00425 struct BufferData *newData = Buffer::Create (newSize);
00426 memcpy (newData->m_data, m_data->m_data + m_start, GetInternalSize ());
00427 m_data->m_count--;
00428 if (m_data->m_count == 0)
00429 {
00430 Buffer::Recycle (m_data);
00431 }
00432 m_data = newData;
00433
00434 int32_t delta = -m_start;
00435 m_zeroAreaStart += delta;
00436 m_zeroAreaEnd += delta;
00437 m_end += delta;
00438 m_start += delta;
00439 m_end += end;
00440
00441
00442 m_data->m_dirtyStart = m_start;
00443 m_data->m_dirtyEnd = m_end;
00444
00445 dirty = true;
00446
00447 HEURISTICS (g_nAddRealloc++);
00448 }
00449 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
00450 LOG_INTERNAL_STATE ("add end=" << end << ", ");
00451 NS_ASSERT (CheckInternalState ());
00452
00453 return dirty;
00454 }
00455
00456 void
00457 Buffer::AddAtEnd (const Buffer &o)
00458 {
00459 NS_LOG_FUNCTION (this << &o);
00460 if (m_data->m_count == 1 &&
00461 m_end == m_zeroAreaEnd &&
00462 m_end == m_data->m_dirtyEnd &&
00463 o.m_start == o.m_zeroAreaStart &&
00464 o.m_zeroAreaEnd - o.m_zeroAreaStart > 0)
00465 {
00466
00467
00468
00469
00470
00471 uint32_t zeroSize = o.m_zeroAreaEnd - o.m_zeroAreaStart;
00472 m_zeroAreaEnd += zeroSize;
00473 m_end = m_zeroAreaEnd;
00474 m_data->m_dirtyEnd = m_zeroAreaEnd;
00475 uint32_t endData = o.m_end - o.m_zeroAreaEnd;
00476 AddAtEnd (endData);
00477 Buffer::Iterator dst = End ();
00478 dst.Prev (endData);
00479 Buffer::Iterator src = o.End ();
00480 src.Prev (endData);
00481 dst.Write (src, o.End ());
00482 NS_ASSERT (CheckInternalState ());
00483 return;
00484 }
00485
00486 Buffer dst = CreateFullCopy ();
00487 Buffer src = o.CreateFullCopy ();
00488
00489 dst.AddAtEnd (src.GetSize ());
00490 Buffer::Iterator destStart = dst.End ();
00491 destStart.Prev (src.GetSize ());
00492 destStart.Write (src.Begin (), src.End ());
00493 *this = dst;
00494 NS_ASSERT (CheckInternalState ());
00495 }
00496
00497 void
00498 Buffer::RemoveAtStart (uint32_t start)
00499 {
00500 NS_LOG_FUNCTION (this << start);
00501 NS_ASSERT (CheckInternalState ());
00502 uint32_t newStart = m_start + start;
00503 if (newStart <= m_zeroAreaStart)
00504 {
00505
00506
00507 m_start = newStart;
00508 }
00509 else if (newStart <= m_zeroAreaEnd)
00510 {
00511
00512
00513 uint32_t delta = newStart - m_zeroAreaStart;
00514 m_start = m_zeroAreaStart;
00515 m_zeroAreaEnd -= delta;
00516 m_end -= delta;
00517 }
00518 else if (newStart <= m_end)
00519 {
00520
00521
00522
00523 NS_ASSERT (m_end >= start);
00524 uint32_t zeroSize = m_zeroAreaEnd - m_zeroAreaStart;
00525 m_start = newStart - zeroSize;
00526 m_end -= zeroSize;
00527 m_zeroAreaStart = m_start;
00528 m_zeroAreaEnd = m_start;
00529 }
00530 else
00531 {
00532
00533 m_end -= m_zeroAreaEnd - m_zeroAreaStart;
00534 m_start = m_end;
00535 m_zeroAreaEnd = m_end;
00536 m_zeroAreaStart = m_end;
00537 }
00538 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
00539 LOG_INTERNAL_STATE ("rem start=" << start << ", ");
00540 NS_ASSERT (CheckInternalState ());
00541 }
00542 void
00543 Buffer::RemoveAtEnd (uint32_t end)
00544 {
00545 NS_LOG_FUNCTION (this << end);
00546 NS_ASSERT (CheckInternalState ());
00547 uint32_t newEnd = m_end - std::min (end, m_end - m_start);
00548 if (newEnd > m_zeroAreaEnd)
00549 {
00550
00551 m_end = newEnd;
00552 }
00553 else if (newEnd > m_zeroAreaStart)
00554 {
00555
00556 m_end = newEnd;
00557 m_zeroAreaEnd = newEnd;
00558 }
00559 else if (newEnd > m_start)
00560 {
00561
00562 m_end = newEnd;
00563 m_zeroAreaEnd = newEnd;
00564 m_zeroAreaStart = newEnd;
00565 }
00566 else
00567 {
00568
00569 m_end = m_start;
00570 m_zeroAreaEnd = m_start;
00571 m_zeroAreaStart = m_start;
00572 }
00573 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
00574 LOG_INTERNAL_STATE ("rem end=" << end << ", ");
00575 NS_ASSERT (CheckInternalState ());
00576 }
00577
00578 Buffer
00579 Buffer::CreateFragment (uint32_t start, uint32_t length) const
00580 {
00581 NS_LOG_FUNCTION (this << start << length);
00582 NS_ASSERT (CheckInternalState ());
00583 Buffer tmp = *this;
00584 tmp.RemoveAtStart (start);
00585 tmp.RemoveAtEnd (GetSize () - (start + length));
00586 NS_ASSERT (CheckInternalState ());
00587 return tmp;
00588 }
00589
00590 Buffer
00591 Buffer::CreateFullCopy (void) const
00592 {
00593 NS_LOG_FUNCTION (this);
00594 NS_ASSERT (CheckInternalState ());
00595 if (m_zeroAreaEnd - m_zeroAreaStart != 0)
00596 {
00597 Buffer tmp;
00598 tmp.AddAtStart (m_zeroAreaEnd - m_zeroAreaStart);
00599 tmp.Begin ().WriteU8 (0, m_zeroAreaEnd - m_zeroAreaStart);
00600 uint32_t dataStart = m_zeroAreaStart - m_start;
00601 tmp.AddAtStart (dataStart);
00602 tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
00603 uint32_t dataEnd = m_end - m_zeroAreaEnd;
00604 tmp.AddAtEnd (dataEnd);
00605 Buffer::Iterator i = tmp.End ();
00606 i.Prev (dataEnd);
00607 i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
00608 NS_ASSERT (tmp.CheckInternalState ());
00609 return tmp;
00610 }
00611 NS_ASSERT (CheckInternalState ());
00612 return *this;
00613 }
00614
00615 int32_t
00616 Buffer::GetCurrentStartOffset (void) const
00617 {
00618 return m_start;
00619 }
00620 int32_t
00621 Buffer::GetCurrentEndOffset (void) const
00622 {
00623 return m_end;
00624 }
00625
00626
00627 void
00628 Buffer::TransformIntoRealBuffer (void) const
00629 {
00630 NS_ASSERT (CheckInternalState ());
00631 Buffer tmp = CreateFullCopy ();
00632 *const_cast<Buffer *> (this) = tmp;
00633 NS_ASSERT (CheckInternalState ());
00634 }
00635
00636
00637 uint8_t const*
00638 Buffer::PeekData (void) const
00639 {
00640 NS_ASSERT (CheckInternalState ());
00641 TransformIntoRealBuffer ();
00642 NS_ASSERT (CheckInternalState ());
00643 return m_data->m_data + m_start;
00644 }
00645
00646
00647
00648
00649
00650
00651 Buffer::Iterator::Iterator ()
00652 : m_zeroStart (0),
00653 m_zeroEnd (0),
00654 m_dataStart (0),
00655 m_dataEnd (0),
00656 m_current (0),
00657 m_data (0)
00658 {}
00659 Buffer::Iterator::Iterator (Buffer const*buffer)
00660 {
00661 Construct (buffer);
00662 m_current = m_dataStart;
00663 }
00664 Buffer::Iterator::Iterator (Buffer const*buffer, bool dummy)
00665 {
00666 Construct (buffer);
00667 m_current = m_dataEnd;
00668 }
00669
00670 void
00671 Buffer::Iterator::Construct (const Buffer *buffer)
00672 {
00673 m_zeroStart = buffer->m_zeroAreaStart;
00674 m_zeroEnd = buffer->m_zeroAreaEnd;
00675 m_dataStart = buffer->m_start;
00676 m_dataEnd = buffer->m_end;
00677 m_data = buffer->m_data->m_data;
00678 }
00679
00680 void
00681 Buffer::Iterator::Next (void)
00682 {
00683 NS_ASSERT (m_current + 1 <= m_dataEnd);
00684 m_current++;
00685 }
00686 void
00687 Buffer::Iterator::Prev (void)
00688 {
00689 NS_ASSERT (m_current >= 1);
00690 m_current--;
00691 }
00692 void
00693 Buffer::Iterator::Next (uint32_t delta)
00694 {
00695 NS_ASSERT (m_current + delta <= m_dataEnd);
00696 m_current += delta;
00697 }
00698 void
00699 Buffer::Iterator::Prev (uint32_t delta)
00700 {
00701 NS_ASSERT (m_current >= delta);
00702 m_current -= delta;
00703 }
00704 uint32_t
00705 Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
00706 {
00707 NS_ASSERT (m_data == o.m_data);
00708 int32_t diff = m_current - o.m_current;
00709 if (diff < 0)
00710 {
00711 return -diff;
00712 }
00713 else
00714 {
00715 return diff;
00716 }
00717 }
00718
00719 bool
00720 Buffer::Iterator::IsEnd (void) const
00721 {
00722 return m_current == m_dataEnd;
00723 }
00724 bool
00725 Buffer::Iterator::IsStart (void) const
00726 {
00727 return m_current == m_dataStart;
00728 }
00729
00730 bool
00731 Buffer::Iterator::CheckNoZero (uint32_t start, uint32_t end) const
00732 {
00733 bool ok = true;
00734 for (uint32_t i = start; i < end; i++)
00735 {
00736 if (!Check (i))
00737 {
00738 ok = false;
00739 }
00740 }
00741 return ok;
00742 }
00743 bool
00744 Buffer::Iterator::Check (uint32_t i) const
00745 {
00746 return i >= m_dataStart &&
00747 !(i >= m_zeroStart && i < m_zeroEnd) &&
00748 i <= m_dataEnd;
00749 }
00750
00751
00752 void
00753 Buffer::Iterator::Write (Iterator start, Iterator end)
00754 {
00755 NS_ASSERT (start.m_data == end.m_data);
00756 NS_ASSERT (start.m_current <= end.m_current);
00757 NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
00758 NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
00759 NS_ASSERT (m_data != start.m_data);
00760 uint32_t size = end.m_current - start.m_current;
00761 Iterator cur = start;
00762 for (uint32_t i = 0; i < size; i++)
00763 {
00764 uint8_t data = cur.ReadU8 ();
00765 WriteU8 (data);
00766 }
00767 }
00768
00769 void
00770 Buffer::Iterator::WriteU16 (uint16_t data)
00771 {
00772 WriteU8 (data & 0xff);
00773 data >>= 8;
00774 WriteU8 (data & 0xff);
00775 }
00776 void
00777 Buffer::Iterator::WriteU32 (uint32_t data)
00778 {
00779 WriteU8 (data & 0xff);
00780 data >>= 8;
00781 WriteU8 (data & 0xff);
00782 data >>= 8;
00783 WriteU8 (data & 0xff);
00784 data >>= 8;
00785 WriteU8 (data & 0xff);
00786 }
00787 void
00788 Buffer::Iterator::WriteU64 (uint64_t data)
00789 {
00790 WriteU8 (data & 0xff);
00791 data >>= 8;
00792 WriteU8 (data & 0xff);
00793 data >>= 8;
00794 WriteU8 (data & 0xff);
00795 data >>= 8;
00796 WriteU8 (data & 0xff);
00797 data >>= 8;
00798 WriteU8 (data & 0xff);
00799 data >>= 8;
00800 WriteU8 (data & 0xff);
00801 data >>= 8;
00802 WriteU8 (data & 0xff);
00803 data >>= 8;
00804 WriteU8 (data & 0xff);
00805 }
00806 void
00807 Buffer::Iterator::WriteHtolsbU16 (uint16_t data)
00808 {
00809 WriteU8 ((data >> 0) & 0xff);
00810 WriteU8 ((data >> 8) & 0xff);
00811 }
00812 void
00813 Buffer::Iterator::WriteHtolsbU32 (uint32_t data)
00814 {
00815 WriteU8 ((data >> 0) & 0xff);
00816 WriteU8 ((data >> 8) & 0xff);
00817 WriteU8 ((data >> 16) & 0xff);
00818 WriteU8 ((data >> 24) & 0xff);
00819 }
00820 void
00821 Buffer::Iterator::WriteHtolsbU64 (uint64_t data)
00822 {
00823 WriteU8 ((data >> 0) & 0xff);
00824 WriteU8 ((data >> 8) & 0xff);
00825 WriteU8 ((data >> 16) & 0xff);
00826 WriteU8 ((data >> 24) & 0xff);
00827 WriteU8 ((data >> 32) & 0xff);
00828 WriteU8 ((data >> 40) & 0xff);
00829 WriteU8 ((data >> 48) & 0xff);
00830 WriteU8 ((data >> 54) & 0xff);
00831 }
00832
00833 void
00834 Buffer::Iterator::WriteHtonU16 (uint16_t data)
00835 {
00836 WriteU8 ((data >> 8) & 0xff);
00837 WriteU8 ((data >> 0) & 0xff);
00838 }
00839 void
00840 Buffer::Iterator::WriteHtonU32 (uint32_t data)
00841 {
00842 WriteU8 ((data >> 24) & 0xff);
00843 WriteU8 ((data >> 16) & 0xff);
00844 WriteU8 ((data >> 8) & 0xff);
00845 WriteU8 ((data >> 0) & 0xff);
00846 }
00847 void
00848 Buffer::Iterator::WriteHtonU64 (uint64_t data)
00849 {
00850 WriteU8 ((data >> 56) & 0xff);
00851 WriteU8 ((data >> 48) & 0xff);
00852 WriteU8 ((data >> 40) & 0xff);
00853 WriteU8 ((data >> 32) & 0xff);
00854 WriteU8 ((data >> 24) & 0xff);
00855 WriteU8 ((data >> 16) & 0xff);
00856 WriteU8 ((data >> 8) & 0xff);
00857 WriteU8 ((data >> 0) & 0xff);
00858 }
00859 void
00860 Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
00861 {
00862 for (uint32_t i = 0; i < size; i++)
00863 {
00864 WriteU8 (buffer[i]);
00865 }
00866 }
00867
00868 uint16_t
00869 Buffer::Iterator::ReadU16 (void)
00870 {
00871 uint8_t byte0 = ReadU8 ();
00872 uint8_t byte1 = ReadU8 ();
00873 uint16_t data = byte1;
00874 data <<= 8;
00875 data |= byte0;
00876
00877 return data;
00878 }
00879 uint32_t
00880 Buffer::Iterator::ReadU32 (void)
00881 {
00882 uint8_t byte0 = ReadU8 ();
00883 uint8_t byte1 = ReadU8 ();
00884 uint8_t byte2 = ReadU8 ();
00885 uint8_t byte3 = ReadU8 ();
00886 uint32_t data = byte3;
00887 data <<= 8;
00888 data |= byte2;
00889 data <<= 8;
00890 data |= byte1;
00891 data <<= 8;
00892 data |= byte0;
00893 return data;
00894 }
00895 uint64_t
00896 Buffer::Iterator::ReadU64 (void)
00897 {
00898 uint8_t byte0 = ReadU8 ();
00899 uint8_t byte1 = ReadU8 ();
00900 uint8_t byte2 = ReadU8 ();
00901 uint8_t byte3 = ReadU8 ();
00902 uint8_t byte4 = ReadU8 ();
00903 uint8_t byte5 = ReadU8 ();
00904 uint8_t byte6 = ReadU8 ();
00905 uint8_t byte7 = ReadU8 ();
00906 uint32_t data = byte7;
00907 data <<= 8;
00908 data |= byte6;
00909 data <<= 8;
00910 data |= byte5;
00911 data <<= 8;
00912 data |= byte4;
00913 data <<= 8;
00914 data |= byte3;
00915 data <<= 8;
00916 data |= byte2;
00917 data <<= 8;
00918 data |= byte1;
00919 data <<= 8;
00920 data |= byte0;
00921
00922 return data;
00923 }
00924 uint16_t
00925 Buffer::Iterator::ReadNtohU16 (void)
00926 {
00927 uint16_t retval = 0;
00928 retval |= ReadU8 ();
00929 retval <<= 8;
00930 retval |= ReadU8 ();
00931 return retval;
00932 }
00933 uint32_t
00934 Buffer::Iterator::ReadNtohU32 (void)
00935 {
00936 uint32_t retval = 0;
00937 retval |= ReadU8 ();
00938 retval <<= 8;
00939 retval |= ReadU8 ();
00940 retval <<= 8;
00941 retval |= ReadU8 ();
00942 retval <<= 8;
00943 retval |= ReadU8 ();
00944 return retval;
00945 }
00946 uint64_t
00947 Buffer::Iterator::ReadNtohU64 (void)
00948 {
00949 uint64_t retval = 0;
00950 retval |= ReadU8 ();
00951 retval <<= 8;
00952 retval |= ReadU8 ();
00953 retval <<= 8;
00954 retval |= ReadU8 ();
00955 retval <<= 8;
00956 retval |= ReadU8 ();
00957 retval <<= 8;
00958 retval |= ReadU8 ();
00959 retval <<= 8;
00960 retval |= ReadU8 ();
00961 retval <<= 8;
00962 retval |= ReadU8 ();
00963 retval <<= 8;
00964 retval |= ReadU8 ();
00965 return retval;
00966 }
00967 uint16_t
00968 Buffer::Iterator::ReadLsbtohU16 (void)
00969 {
00970 uint8_t byte0 = ReadU8 ();
00971 uint8_t byte1 = ReadU8 ();
00972 uint16_t data = byte1;
00973 data <<= 8;
00974 data |= byte0;
00975 return data;
00976 }
00977 uint32_t
00978 Buffer::Iterator::ReadLsbtohU32 (void)
00979 {
00980 uint8_t byte0 = ReadU8 ();
00981 uint8_t byte1 = ReadU8 ();
00982 uint8_t byte2 = ReadU8 ();
00983 uint8_t byte3 = ReadU8 ();
00984 uint32_t data = byte3;
00985 data <<= 8;
00986 data |= byte2;
00987 data <<= 8;
00988 data |= byte1;
00989 data <<= 8;
00990 data |= byte0;
00991 return data;
00992 }
00993 uint64_t
00994 Buffer::Iterator::ReadLsbtohU64 (void)
00995 {
00996 uint8_t byte0 = ReadU8 ();
00997 uint8_t byte1 = ReadU8 ();
00998 uint8_t byte2 = ReadU8 ();
00999 uint8_t byte3 = ReadU8 ();
01000 uint8_t byte4 = ReadU8 ();
01001 uint8_t byte5 = ReadU8 ();
01002 uint8_t byte6 = ReadU8 ();
01003 uint8_t byte7 = ReadU8 ();
01004 uint32_t data = byte7;
01005 data <<= 8;
01006 data |= byte6;
01007 data <<= 8;
01008 data |= byte5;
01009 data <<= 8;
01010 data |= byte4;
01011 data <<= 8;
01012 data |= byte3;
01013 data <<= 8;
01014 data |= byte2;
01015 data <<= 8;
01016 data |= byte1;
01017 data <<= 8;
01018 data |= byte0;
01019
01020 return data;
01021 }
01022 void
01023 Buffer::Iterator::Read (uint8_t *buffer, uint32_t size)
01024 {
01025 for (uint32_t i = 0; i < size; i++)
01026 {
01027 buffer[i] = ReadU8 ();
01028 }
01029 }
01030
01031 #ifndef BUFFER_USE_INLINE
01032
01033 void
01034 Buffer::Iterator::WriteU8 (uint8_t data)
01035 {
01036 if (m_current < m_dataStart)
01037 {
01038
01039 NS_ASSERT (false);
01040 }
01041 else if (m_current < m_zeroStart)
01042 {
01043 m_data[m_current] = data;
01044 m_current++;
01045 }
01046 else if (m_current < m_zeroEnd)
01047 {
01048
01049 NS_ASSERT (false);
01050 }
01051 else if (m_current < m_dataEnd)
01052 {
01053 m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
01054 m_current++;
01055 }
01056 else
01057 {
01058
01059 NS_ASSERT (false);
01060 }
01061 }
01062
01063 void
01064 Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
01065 {
01066 for (uint32_t i = 0; i < len; i++)
01067 {
01068 WriteU8 (data);
01069 }
01070 }
01071
01072 uint8_t
01073 Buffer::Iterator::ReadU8 (void)
01074 {
01075 if (m_current < m_dataStart)
01076 {
01077
01078 NS_ASSERT (false);
01079 }
01080 else if (m_current < m_zeroStart)
01081 {
01082 uint8_t data = m_data[m_current];
01083 m_current++;
01084 return data;
01085 }
01086 else if (m_current < m_zeroEnd)
01087 {
01088 m_current++;
01089 return 0;
01090 }
01091 else if (m_current < m_dataEnd)
01092 {
01093 uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
01094 m_current++;
01095 return data;
01096 }
01097 else
01098 {
01099
01100 NS_ASSERT (false);
01101 }
01102
01103 return 0;
01104 }
01105
01106 #endif
01107
01108 uint16_t
01109 Buffer::Iterator::CalculateIpChecksum(uint16_t size)
01110 {
01111 return CalculateIpChecksum(size, 0);
01112 }
01113
01114 uint16_t
01115 Buffer::Iterator::CalculateIpChecksum(uint16_t size, uint32_t initialChecksum)
01116 {
01117
01118 uint32_t sum = initialChecksum;
01119
01120 for (int j = 0; j < size/2; j++)
01121 sum += ReadU16 ();
01122
01123 if (size & 1)
01124 sum += ReadU8 ();
01125
01126 while (sum >> 16)
01127 sum = (sum & 0xffff) + (sum >> 16);
01128 return ~sum;
01129 }
01130
01131 uint32_t
01132 Buffer::Iterator::GetSize (void) const
01133 {
01134 return m_dataEnd - m_dataStart;
01135 }
01136
01137 }
01138
01139
01140 #ifdef RUN_SELF_TESTS
01141
01142 #include "ns3/test.h"
01143 #include "ns3/random-variable.h"
01144 #include <iomanip>
01145
01146
01147 namespace ns3 {
01148
01149 class BufferTest: public Test {
01150 private:
01151 bool EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[]);
01152 public:
01153 virtual bool RunTests (void);
01154 BufferTest ();
01155 };
01156
01157
01158 BufferTest::BufferTest ()
01159 : Test ("Buffer") {}
01160
01161 bool
01162 BufferTest::EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[])
01163 {
01164 bool success = true;
01165 uint8_t *expected = array;
01166 uint8_t const*got;
01167 got = b.PeekData ();
01168 for (uint32_t j = 0; j < n; j++)
01169 {
01170 if (got[j] != expected[j])
01171 {
01172 success = false;
01173 }
01174 }
01175 if (!success)
01176 {
01177 Failure () << "Buffer -- ";
01178 Failure () << "expected: n=";
01179 Failure () << n << ", ";
01180 Failure ().setf (std::ios::hex, std::ios::basefield);
01181 for (uint32_t j = 0; j < n; j++)
01182 {
01183 Failure () << (uint16_t)expected[j] << " ";
01184 }
01185 Failure ().setf (std::ios::dec, std::ios::basefield);
01186 Failure () << "got: ";
01187 Failure ().setf (std::ios::hex, std::ios::basefield);
01188 for (uint32_t j = 0; j < n; j++)
01189 {
01190 Failure () << (uint16_t)got[j] << " ";
01191 }
01192 Failure () << std::endl;
01193 }
01194 return success;
01195 }
01196
01197
01198
01199
01200
01201 #define ENSURE_WRITTEN_BYTES(buffer, n, ...) \
01202 { \
01203 uint8_t bytes[] = {__VA_ARGS__}; \
01204 if (!EnsureWrittenBytes (buffer, n , bytes)) \
01205 { \
01206 result = false; \
01207 } \
01208 }
01209
01210 bool
01211 BufferTest::RunTests (void)
01212 {
01213 bool result = true;
01214 Buffer buffer;
01215 Buffer::Iterator i;
01216 buffer.AddAtStart (6);
01217 i = buffer.Begin ();
01218 i.WriteU8 (0x66);
01219 ENSURE_WRITTEN_BYTES (buffer, 1, 0x66);
01220 i = buffer.Begin ();
01221 i.WriteU8 (0x67);
01222 ENSURE_WRITTEN_BYTES (buffer, 1, 0x67);
01223 i.WriteHtonU16 (0x6568);
01224 i = buffer.Begin ();
01225 ENSURE_WRITTEN_BYTES (buffer, 3, 0x67, 0x65, 0x68);
01226 i.WriteHtonU16 (0x6369);
01227 ENSURE_WRITTEN_BYTES (buffer, 3, 0x63, 0x69, 0x68);
01228 i.WriteHtonU32 (0xdeadbeaf);
01229 ENSURE_WRITTEN_BYTES (buffer, 6, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
01230 buffer.AddAtStart (2);
01231 i = buffer.Begin ();
01232 i.WriteU16 (0);
01233 ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
01234 buffer.AddAtEnd (2);
01235 i = buffer.Begin ();
01236 i.Next (8);
01237 i.WriteU16 (0);
01238 ENSURE_WRITTEN_BYTES (buffer, 10, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
01239 buffer.RemoveAtStart (3);
01240 i = buffer.Begin ();
01241 ENSURE_WRITTEN_BYTES (buffer, 7, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
01242 buffer.RemoveAtEnd (4);
01243 i = buffer.Begin ();
01244 ENSURE_WRITTEN_BYTES (buffer, 3, 0x69, 0xde, 0xad);
01245 buffer.AddAtStart (1);
01246 i = buffer.Begin ();
01247 i.WriteU8 (0xff);
01248 ENSURE_WRITTEN_BYTES (buffer, 4, 0xff, 0x69, 0xde, 0xad);
01249 buffer.AddAtEnd (1);
01250 i = buffer.Begin ();
01251 i.Next (4);
01252 i.WriteU8 (0xff);
01253 i.Prev (2);
01254 uint16_t saved = i.ReadU16 ();
01255 i.Prev (2);
01256 i.WriteHtonU16 (0xff00);
01257 i.Prev (2);
01258 if (i.ReadNtohU16 () != 0xff00)
01259 {
01260 result = false;
01261 }
01262 i.Prev (2);
01263 i.WriteU16 (saved);
01264 ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
01265 Buffer o = buffer;
01266 ENSURE_WRITTEN_BYTES (o, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
01267 o.AddAtStart (1);
01268 i = o.Begin ();
01269 i.WriteU8 (0xfe);
01270 ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
01271 buffer.AddAtStart (2);
01272 i = buffer.Begin ();
01273 i.WriteU8 (0xfd);
01274 i.WriteU8 (0xfd);
01275 ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
01276 ENSURE_WRITTEN_BYTES (buffer, 7, 0xfd, 0xfd, 0xff, 0x69, 0xde, 0xad, 0xff);
01277
01278
01279 {
01280 Buffer a = o;
01281 a = a;
01282 }
01283
01284
01285 buffer = Buffer (5);
01286 ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
01287 buffer.RemoveAtStart (1);
01288 ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
01289 buffer.AddAtStart (1);
01290 buffer.Begin ().WriteU8 (0xff);
01291 ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0, 0, 0, 0);
01292 buffer.RemoveAtStart(3);
01293 ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
01294 buffer.AddAtStart (4);
01295 buffer.Begin ().WriteHtonU32 (0xdeadbeaf);
01296 ENSURE_WRITTEN_BYTES (buffer, 6, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
01297 buffer.RemoveAtStart (2);
01298 ENSURE_WRITTEN_BYTES (buffer, 4, 0xbe, 0xaf, 0, 0);
01299 buffer.AddAtEnd (4);
01300 i = buffer.Begin ();
01301 i.Next (4);
01302 i.WriteHtonU32 (0xdeadbeaf);
01303 ENSURE_WRITTEN_BYTES (buffer, 8, 0xbe, 0xaf, 0, 0, 0xde, 0xad, 0xbe, 0xaf);
01304 buffer.RemoveAtStart (5);
01305 ENSURE_WRITTEN_BYTES (buffer, 3, 0xad, 0xbe, 0xaf);
01306
01307 buffer = Buffer (5);
01308 ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
01309 buffer.RemoveAtEnd (1);
01310 ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
01311 buffer.AddAtEnd (2);
01312 i = buffer.Begin ();
01313 i.Next (4);
01314 i.WriteU8 (0xab);
01315 i.WriteU8 (0xac);
01316 ENSURE_WRITTEN_BYTES (buffer, 6, 0, 0, 0, 0, 0xab, 0xac);
01317 buffer.RemoveAtEnd (1);
01318 ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0xab);
01319 buffer.RemoveAtEnd (3);
01320 ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
01321 buffer.AddAtEnd (6);
01322 i = buffer.Begin ();
01323 i.Next (2);
01324 i.WriteU8 (0xac);
01325 i.WriteU8 (0xad);
01326 i.WriteU8 (0xae);
01327 i.WriteU8 (0xaf);
01328 i.WriteU8 (0xba);
01329 i.WriteU8 (0xbb);
01330 ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
01331 buffer.AddAtStart (3);
01332 i = buffer.Begin ();
01333 i.WriteU8 (0x30);
01334 i.WriteU8 (0x31);
01335 i.WriteU8 (0x32);
01336 ENSURE_WRITTEN_BYTES (buffer, 11, 0x30, 0x31, 0x32, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
01337 buffer.RemoveAtEnd (9);
01338 ENSURE_WRITTEN_BYTES (buffer, 2, 0x30, 0x31);
01339 buffer = Buffer (3);
01340 buffer.AddAtEnd (2);
01341 i = buffer.Begin ();
01342 i.Next (3);
01343 i.WriteHtonU16 (0xabcd);
01344 buffer.AddAtStart (1);
01345 buffer.Begin ().WriteU8 (0x21);
01346 ENSURE_WRITTEN_BYTES (buffer, 6, 0x21, 0, 0, 0, 0xab, 0xcd);
01347 buffer.RemoveAtEnd (8);
01348 if (buffer.GetSize () != 0)
01349 {
01350 result = false;
01351 }
01352
01353 buffer = Buffer (6);
01354 buffer.AddAtStart (9);
01355 buffer.AddAtEnd (3);
01356 i = buffer.End ();
01357 i.Prev (1);
01358 i.WriteU8 (1, 1);
01359
01360 buffer = Buffer (6);
01361 buffer.AddAtStart (3);
01362 buffer.RemoveAtEnd (8);
01363 buffer.AddAtEnd (4);
01364 i = buffer.End ();
01365 i.Prev (4);
01366 i.WriteU8 (1, 4);
01367
01368 buffer = Buffer (1);
01369 buffer.AddAtEnd (100);
01370 i = buffer.End ();
01371 i.Prev (100);
01372 i.WriteU8 (1, 100);
01373
01374 #if 0
01375 buffer = Buffer (10);
01376 ENSURE_WRITTEN_BYTES (buffer, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
01377 buffer.Begin ().WriteU8 (1);
01378 ENSURE_WRITTEN_BYTES (buffer, 10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
01379 #endif
01380
01381
01382 {
01383 const uint32_t actualSize = 72602;
01384 const uint32_t chunkSize = 67624;
01385 UniformVariable bytesRng (0, 256);
01386
01387 Buffer inputBuffer;
01388 Buffer outputBuffer;
01389
01390 inputBuffer.AddAtEnd (actualSize);
01391 {
01392 Buffer::Iterator iter = inputBuffer.Begin ();
01393 for (uint32_t i = 0; i < actualSize; i++)
01394 iter.WriteU8 (static_cast<uint8_t> (bytesRng.GetValue ()));
01395 }
01396
01397 outputBuffer.AddAtEnd (chunkSize);
01398 Buffer::Iterator iter = outputBuffer.End ();
01399 iter.Prev (chunkSize);
01400 iter.Write (inputBuffer.PeekData (), chunkSize);
01401
01402 NS_TEST_ASSERT (memcmp (inputBuffer.PeekData (), outputBuffer.PeekData (), chunkSize) == 0);
01403 }
01404
01405 buffer = Buffer (5);
01406 buffer.AddAtEnd (2);
01407 i = buffer.End ();
01408 i.Prev (2);
01409 i.WriteU8 (0);
01410 i.WriteU8 (0x66);
01411 ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
01412 Buffer frag0 = buffer.CreateFragment (0, 2);
01413 ENSURE_WRITTEN_BYTES (frag0, 2, 0x00, 0x00);
01414 Buffer frag1 = buffer.CreateFragment (2, 5);
01415 ENSURE_WRITTEN_BYTES (frag1, 5, 0x00, 0x00, 0x00, 0x00, 0x66);
01416 frag0.AddAtEnd (frag1);
01417 ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
01418 ENSURE_WRITTEN_BYTES (frag0, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
01419
01420 return result;
01421 }
01422
01423
01424
01425 static BufferTest gBufferTest;
01426
01427 }
01428
01429 #endif
01430
01431