bug 639: Buffer::CopyData is buggy.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3 * Copyright (c) 2005,2006,2007 INRIA
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
21 #include "ns3/assert.h"
23 #include "ns3/fatal-error.h"
26 NS_LOG_COMPONENT_DEFINE ("Buffer");
28 #define LOG_INTERNAL_STATE(y) \
29 NS_LOG_LOGIC (y << "start="<<m_start<<", end="<<m_end<<", zero start="<<m_zeroAreaStart<< \
30 ", zero end="<<m_zeroAreaEnd<<", count="<<m_data->m_count<<", size="<<m_data->m_size<< \
31 ", dirty start="<<m_data->m_dirtyStart<<", dirty end="<<m_data->m_dirtyEnd)
33 #ifdef BUFFER_HEURISTICS
34 #define HEURISTICS(x) x
39 //#define PRINT_STATS 1
44 * This data structure is variable-sized through its last member whose size
45 * is determined at allocation time and stored in the m_size field.
47 * The so-called "dirty area" describes the area in the buffer which
48 * has been reserved and used by a user. Multiple Buffer instances
49 * may reference the same BufferData object instance and may
50 * reference different parts of the underlying byte buffer. The
51 * "dirty area" is union of all the areas referenced by the Buffer
52 * instances which reference the same BufferData instance.
53 * New user data can be safely written only outside of the "dirty
54 * area" if the reference count is higher than 1 (that is, if
55 * more than one Buffer instance references the same BufferData).
58 /* The reference count of an instance of this data structure.
59 * Each buffer which references an instance holds a count.
62 /* the size of the m_data field below.
65 /* offset from the start of the m_data field below to the
66 * start of the area in which user bytes were written.
68 uint32_t m_dirtyStart;
69 /* offset from the start of the m_data field below to the
70 * end of the area in which user bytes were written.
73 /* The real data buffer holds _at least_ one byte.
74 * Its real size is stored in the m_size field.
78 class BufferDataList : public std::vector<struct BufferData*>
84 static struct BufferData *BufferAllocate (uint32_t reqSize);
86 static void BufferDeallocate (struct BufferData *data);
93 #ifdef BUFFER_HEURISTICS
94 static uint32_t g_recommendedStart = 0;
95 static uint64_t g_nAddNoRealloc = 0;
96 static uint64_t g_nAddRealloc = 0;
97 static BufferDataList g_freeList;
98 static uint32_t g_maxSize = 0;
99 static uint64_t g_nAllocs = 0;
100 static uint64_t g_nCreates = 0;
101 #endif /* BUFFER_HEURISTICS */
103 BufferDataList::~BufferDataList ()
106 #ifdef BUFFER_HEURISTICS
108 efficiency = g_nAllocs;
109 efficiency /= g_nCreates;
110 std::cout <<"buffer free list efficiency="<<efficiency<<" (lower is better)" << std::endl;
111 std::cout <<"buffer free list max size="<<g_maxSize<<std::endl;
112 std::cout <<"buffer free list recommended start="<<g_recommendedStart<<std::endl;
113 double addEfficiency;
114 addEfficiency = g_nAddRealloc;
115 addEfficiency /= g_nAddNoRealloc;
116 std::cout <<"buffer add efficiency=" << addEfficiency << " (lower is better)"<<std::endl;
117 //std::cout <<"n add reallocs="<< g_nAddRealloc << std::endl;
118 //std::cout <<"n add no reallocs="<< g_nAddNoRealloc << std::endl;
119 #endif /* BUFFER_HEURISTICS */
120 #endif /* PRINT_STATS */
121 for (BufferDataList::iterator i = begin ();
124 BufferDeallocate (*i);
129 BufferAllocate (uint32_t reqSize)
135 NS_ASSERT (reqSize >= 1);
136 uint32_t size = reqSize - 1 + sizeof (struct BufferData);
137 uint8_t *b = new uint8_t [size];
138 struct BufferData *data = reinterpret_cast<struct BufferData*>(b);
139 data->m_size = reqSize;
145 BufferDeallocate (struct BufferData *data)
147 NS_ASSERT (data->m_count == 0);
148 uint8_t *buf = reinterpret_cast<uint8_t *> (data);
151 #ifdef BUFFER_HEURISTICS
153 Buffer::Recycle (struct BufferData *data)
155 NS_ASSERT (data->m_count == 0);
156 g_maxSize = std::max (g_maxSize, data->m_size);
157 /* feed into free list */
158 if (data->m_size < g_maxSize ||
159 g_freeList.size () > 1000)
161 BufferDeallocate (data);
165 g_freeList.push_back (data);
170 Buffer::Create (uint32_t dataSize)
172 /* try to find a buffer correctly sized. */
174 while (!g_freeList.empty ())
176 struct BufferData *data = g_freeList.back ();
177 g_freeList.pop_back ();
178 if (data->m_size >= dataSize)
183 BufferDeallocate (data);
186 struct BufferData *data = BufferAllocate (dataSize);
187 NS_ASSERT (data->m_count == 1);
192 Buffer::Recycle (struct BufferData *data)
194 NS_ASSERT (data->m_count == 0);
195 BufferDeallocate (data);
199 Buffer::Create (uint32_t size)
201 return BufferAllocate (size);
207 NS_LOG_FUNCTION (this);
211 Buffer::Buffer (uint32_t dataSize)
213 NS_LOG_FUNCTION (this << dataSize);
214 Initialize (dataSize);
218 Buffer::CheckInternalState (void) const
221 m_start <= m_zeroAreaStart &&
222 m_zeroAreaStart <= m_zeroAreaEnd &&
223 m_zeroAreaEnd <= m_end;
225 m_start >= m_data->m_dirtyStart &&
226 m_end <= m_data->m_dirtyEnd;
227 bool internalSizeOk = m_end - (m_zeroAreaEnd - m_zeroAreaStart) <= m_data->m_size &&
228 m_start <= m_data->m_size &&
229 m_zeroAreaStart <= m_data->m_size;
231 bool ok = m_data->m_count > 0 && offsetsOk && dirtyOk && internalSizeOk;
234 LOG_INTERNAL_STATE ("check " << this <<
235 ", " << (offsetsOk?"true":"false") <<
236 ", " << (dirtyOk?"true":"false") <<
237 ", " << (internalSizeOk?"true":"false") << " ");
243 Buffer::Initialize (uint32_t zeroSize)
245 NS_LOG_FUNCTION (this << zeroSize);
246 m_data = Buffer::Create (0);
247 #ifdef BUFFER_HEURISTICS
248 m_start = std::min (m_data->m_size, g_recommendedStart);
249 m_maxZeroAreaStart = m_start;
252 #endif /* BUFFER_HEURISTICS */
253 m_zeroAreaStart = m_start;
254 m_zeroAreaEnd = m_zeroAreaStart + zeroSize;
255 m_end = m_zeroAreaEnd;
256 m_data->m_dirtyStart = m_start;
257 m_data->m_dirtyEnd = m_end;
258 NS_ASSERT (CheckInternalState ());
261 Buffer::Buffer (Buffer const&o)
263 #ifdef BUFFER_HEURISTICS
264 m_maxZeroAreaStart (o.m_zeroAreaStart),
266 m_zeroAreaStart (o.m_zeroAreaStart),
267 m_zeroAreaEnd (o.m_zeroAreaEnd),
271 NS_LOG_FUNCTION (this << &o);
273 NS_ASSERT (CheckInternalState ());
277 Buffer::operator = (Buffer const&o)
279 NS_LOG_FUNCTION (this << &o);
280 NS_ASSERT (CheckInternalState ());
281 if (m_data != o.m_data)
283 // not assignment to self.
285 if (m_data->m_count == 0)
293 g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart);
294 m_maxZeroAreaStart = o.m_maxZeroAreaStart;
296 m_zeroAreaStart = o.m_zeroAreaStart;
297 m_zeroAreaEnd = o.m_zeroAreaEnd;
300 NS_ASSERT (CheckInternalState ());
306 NS_LOG_FUNCTION (this);
307 NS_ASSERT (CheckInternalState ());
308 HEURISTICS (g_recommendedStart = std::max (g_recommendedStart, m_maxZeroAreaStart));
310 if (m_data->m_count == 0)
317 Buffer::GetSize (void) const
319 NS_ASSERT (CheckInternalState ());
320 return m_end - m_start;
324 Buffer::Begin (void) const
326 NS_ASSERT (CheckInternalState ());
327 return Buffer::Iterator (this);
330 Buffer::End (void) const
332 NS_ASSERT (CheckInternalState ());
333 return Buffer::Iterator (this, false);
337 Buffer::GetInternalSize (void) const
339 return m_zeroAreaStart - m_start + m_end - m_zeroAreaEnd;
342 Buffer::GetInternalEnd (void) const
344 return m_end - (m_zeroAreaEnd - m_zeroAreaStart);
348 Buffer::AddAtStart (uint32_t start)
350 NS_LOG_FUNCTION (this << start);
352 NS_ASSERT (CheckInternalState ());
353 bool isDirty = m_data->m_count > 1 && m_start > m_data->m_dirtyStart;
354 if (m_start >= start && !isDirty)
356 /* enough space in the buffer and not dirty.
358 * Before: |*****---------***|
359 * After: |***..---------***|
361 NS_ASSERT (m_data->m_count == 1 || m_start == m_data->m_dirtyStart);
363 dirty = m_start > m_data->m_dirtyStart;
365 m_data->m_dirtyStart = m_start;
366 HEURISTICS (g_nAddNoRealloc++);
370 uint32_t newSize = GetInternalSize () + start;
371 struct BufferData *newData = Buffer::Create (newSize);
372 memcpy (newData->m_data + start, m_data->m_data + m_start, GetInternalSize ());
374 if (m_data->m_count == 0)
376 Buffer::Recycle (m_data);
380 int32_t delta = start - m_start;
382 m_zeroAreaStart += delta;
383 m_zeroAreaEnd += delta;
388 m_data->m_dirtyStart = m_start;
389 m_data->m_dirtyEnd = m_end;
393 HEURISTICS (g_nAddRealloc++);
395 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
396 LOG_INTERNAL_STATE ("add start=" << start << ", ");
397 NS_ASSERT (CheckInternalState ());
401 Buffer::AddAtEnd (uint32_t end)
403 NS_LOG_FUNCTION (this << end);
405 NS_ASSERT (CheckInternalState ());
406 bool isDirty = m_data->m_count > 1 && m_end < m_data->m_dirtyEnd;
407 if (GetInternalEnd () + end <= m_data->m_size && !isDirty)
409 /* enough space in buffer and not dirty
411 * Before: |**----*****|
412 * After: |**----...**|
414 NS_ASSERT (m_data->m_count == 1 || m_end == m_data->m_dirtyEnd);
416 // update dirty area.
417 m_data->m_dirtyEnd = m_end;
419 dirty = m_end < m_data->m_dirtyEnd;
421 HEURISTICS (g_nAddNoRealloc++);
425 uint32_t newSize = GetInternalSize () + end;
426 struct BufferData *newData = Buffer::Create (newSize);
427 memcpy (newData->m_data, m_data->m_data + m_start, GetInternalSize ());
429 if (m_data->m_count == 0)
431 Buffer::Recycle (m_data);
435 int32_t delta = -m_start;
436 m_zeroAreaStart += delta;
437 m_zeroAreaEnd += delta;
443 m_data->m_dirtyStart = m_start;
444 m_data->m_dirtyEnd = m_end;
448 HEURISTICS (g_nAddRealloc++);
450 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
451 LOG_INTERNAL_STATE ("add end=" << end << ", ");
452 NS_ASSERT (CheckInternalState ());
458 Buffer::AddAtEnd (const Buffer &o)
460 NS_LOG_FUNCTION (this << &o);
461 if (m_data->m_count == 1 &&
462 m_end == m_zeroAreaEnd &&
463 m_end == m_data->m_dirtyEnd &&
464 o.m_start == o.m_zeroAreaStart &&
465 o.m_zeroAreaEnd - o.m_zeroAreaStart > 0)
468 * This is an optimization which kicks in when
469 * we attempt to aggregate two buffers which contain
470 * adjacent zero areas.
472 uint32_t zeroSize = o.m_zeroAreaEnd - o.m_zeroAreaStart;
473 m_zeroAreaEnd += zeroSize;
474 m_end = m_zeroAreaEnd;
475 m_data->m_dirtyEnd = m_zeroAreaEnd;
476 uint32_t endData = o.m_end - o.m_zeroAreaEnd;
478 Buffer::Iterator dst = End ();
480 Buffer::Iterator src = o.End ();
482 dst.Write (src, o.End ());
483 NS_ASSERT (CheckInternalState ());
487 Buffer dst = CreateFullCopy ();
488 Buffer src = o.CreateFullCopy ();
490 dst.AddAtEnd (src.GetSize ());
491 Buffer::Iterator destStart = dst.End ();
492 destStart.Prev (src.GetSize ());
493 destStart.Write (src.Begin (), src.End ());
495 NS_ASSERT (CheckInternalState ());
499 Buffer::RemoveAtStart (uint32_t start)
501 NS_LOG_FUNCTION (this << start);
502 NS_ASSERT (CheckInternalState ());
503 uint32_t newStart = m_start + start;
504 if (newStart <= m_zeroAreaStart)
506 /* only remove start of buffer
510 else if (newStart <= m_zeroAreaEnd)
512 /* remove start of buffer _and_ start of zero area
514 uint32_t delta = newStart - m_zeroAreaStart;
515 m_start = m_zeroAreaStart;
516 m_zeroAreaEnd -= delta;
519 else if (newStart <= m_end)
521 /* remove start of buffer, complete zero area, and part
524 NS_ASSERT (m_end >= start);
525 uint32_t zeroSize = m_zeroAreaEnd - m_zeroAreaStart;
526 m_start = newStart - zeroSize;
528 m_zeroAreaStart = m_start;
529 m_zeroAreaEnd = m_start;
533 /* remove all buffer */
534 m_end -= m_zeroAreaEnd - m_zeroAreaStart;
536 m_zeroAreaEnd = m_end;
537 m_zeroAreaStart = m_end;
539 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
540 LOG_INTERNAL_STATE ("rem start=" << start << ", ");
541 NS_ASSERT (CheckInternalState ());
544 Buffer::RemoveAtEnd (uint32_t end)
546 NS_LOG_FUNCTION (this << end);
547 NS_ASSERT (CheckInternalState ());
548 uint32_t newEnd = m_end - std::min (end, m_end - m_start);
549 if (newEnd > m_zeroAreaEnd)
551 /* remove part of end of buffer */
554 else if (newEnd > m_zeroAreaStart)
556 /* remove end of buffer, part of zero area */
558 m_zeroAreaEnd = newEnd;
560 else if (newEnd > m_start)
562 /* remove end of buffer, zero area, part of start of buffer */
564 m_zeroAreaEnd = newEnd;
565 m_zeroAreaStart = newEnd;
569 /* remove all buffer */
571 m_zeroAreaEnd = m_start;
572 m_zeroAreaStart = m_start;
574 HEURISTICS (m_maxZeroAreaStart = std::max (m_maxZeroAreaStart, m_zeroAreaStart));
575 LOG_INTERNAL_STATE ("rem end=" << end << ", ");
576 NS_ASSERT (CheckInternalState ());
580 Buffer::CreateFragment (uint32_t start, uint32_t length) const
582 NS_LOG_FUNCTION (this << start << length);
583 NS_ASSERT (CheckInternalState ());
585 tmp.RemoveAtStart (start);
586 tmp.RemoveAtEnd (GetSize () - (start + length));
587 NS_ASSERT (CheckInternalState ());
592 Buffer::CreateFullCopy (void) const
594 NS_LOG_FUNCTION (this);
595 NS_ASSERT (CheckInternalState ());
596 if (m_zeroAreaEnd - m_zeroAreaStart != 0)
599 tmp.AddAtStart (m_zeroAreaEnd - m_zeroAreaStart);
600 tmp.Begin ().WriteU8 (0, m_zeroAreaEnd - m_zeroAreaStart);
601 uint32_t dataStart = m_zeroAreaStart - m_start;
602 tmp.AddAtStart (dataStart);
603 tmp.Begin ().Write (m_data->m_data+m_start, dataStart);
604 uint32_t dataEnd = m_end - m_zeroAreaEnd;
605 tmp.AddAtEnd (dataEnd);
606 Buffer::Iterator i = tmp.End ();
608 i.Write (m_data->m_data+m_zeroAreaStart,dataEnd);
609 NS_ASSERT (tmp.CheckInternalState ());
612 NS_ASSERT (CheckInternalState ());
617 Buffer::GetCurrentStartOffset (void) const
622 Buffer::GetCurrentEndOffset (void) const
629 Buffer::TransformIntoRealBuffer (void) const
631 NS_ASSERT (CheckInternalState ());
632 Buffer tmp = CreateFullCopy ();
633 *const_cast<Buffer *> (this) = tmp;
634 NS_ASSERT (CheckInternalState ());
639 Buffer::PeekData (void) const
641 NS_ASSERT (CheckInternalState ());
642 TransformIntoRealBuffer ();
643 NS_ASSERT (CheckInternalState ());
644 return m_data->m_data + m_start;
648 Buffer::CopyData(std::ostream *os, uint32_t size) const
652 uint32_t tmpsize = std::min (m_zeroAreaStart-m_start, size);
653 os->write((const char*)(m_data->m_data + m_start), tmpsize);
656 size -= m_zeroAreaStart-m_start;
657 tmpsize = std::min (m_zeroAreaEnd - m_zeroAreaStart, size);
659 for (uint32_t i = 0; i < tmpsize; ++i)
661 os->write (&zero, 1);
666 tmpsize = std::min (m_end - m_zeroAreaEnd, size);
667 os->write ((const char*)(m_data->m_data + m_zeroAreaStart), tmpsize);
673 /******************************************************
674 * The buffer iterator below.
675 ******************************************************/
678 Buffer::Iterator::Iterator ()
686 Buffer::Iterator::Iterator (Buffer const*buffer)
689 m_current = m_dataStart;
691 Buffer::Iterator::Iterator (Buffer const*buffer, bool dummy)
694 m_current = m_dataEnd;
698 Buffer::Iterator::Construct (const Buffer *buffer)
700 m_zeroStart = buffer->m_zeroAreaStart;
701 m_zeroEnd = buffer->m_zeroAreaEnd;
702 m_dataStart = buffer->m_start;
703 m_dataEnd = buffer->m_end;
704 m_data = buffer->m_data->m_data;
708 Buffer::Iterator::Next (void)
710 NS_ASSERT (m_current + 1 <= m_dataEnd);
714 Buffer::Iterator::Prev (void)
716 NS_ASSERT (m_current >= 1);
720 Buffer::Iterator::Next (uint32_t delta)
722 NS_ASSERT (m_current + delta <= m_dataEnd);
726 Buffer::Iterator::Prev (uint32_t delta)
728 NS_ASSERT (m_current >= delta);
732 Buffer::Iterator::GetDistanceFrom (Iterator const &o) const
734 NS_ASSERT (m_data == o.m_data);
735 int32_t diff = m_current - o.m_current;
747 Buffer::Iterator::IsEnd (void) const
749 return m_current == m_dataEnd;
752 Buffer::Iterator::IsStart (void) const
754 return m_current == m_dataStart;
758 Buffer::Iterator::CheckNoZero (uint32_t start, uint32_t end) const
761 for (uint32_t i = start; i < end; i++)
771 Buffer::Iterator::Check (uint32_t i) const
773 return i >= m_dataStart &&
774 !(i >= m_zeroStart && i < m_zeroEnd) &&
780 Buffer::Iterator::Write (Iterator start, Iterator end)
782 NS_ASSERT (start.m_data == end.m_data);
783 NS_ASSERT (start.m_current <= end.m_current);
784 NS_ASSERT (start.m_zeroStart == end.m_zeroStart);
785 NS_ASSERT (start.m_zeroEnd == end.m_zeroEnd);
786 NS_ASSERT (m_data != start.m_data);
787 uint32_t size = end.m_current - start.m_current;
788 Iterator cur = start;
789 for (uint32_t i = 0; i < size; i++)
791 uint8_t data = cur.ReadU8 ();
797 Buffer::Iterator::WriteU16 (uint16_t data)
799 WriteU8 (data & 0xff);
801 WriteU8 (data & 0xff);
804 Buffer::Iterator::WriteU32 (uint32_t data)
806 WriteU8 (data & 0xff);
808 WriteU8 (data & 0xff);
810 WriteU8 (data & 0xff);
812 WriteU8 (data & 0xff);
815 Buffer::Iterator::WriteU64 (uint64_t data)
817 WriteU8 (data & 0xff);
819 WriteU8 (data & 0xff);
821 WriteU8 (data & 0xff);
823 WriteU8 (data & 0xff);
825 WriteU8 (data & 0xff);
827 WriteU8 (data & 0xff);
829 WriteU8 (data & 0xff);
831 WriteU8 (data & 0xff);
834 Buffer::Iterator::WriteHtolsbU16 (uint16_t data)
836 WriteU8 ((data >> 0) & 0xff);
837 WriteU8 ((data >> 8) & 0xff);
840 Buffer::Iterator::WriteHtolsbU32 (uint32_t data)
842 WriteU8 ((data >> 0) & 0xff);
843 WriteU8 ((data >> 8) & 0xff);
844 WriteU8 ((data >> 16) & 0xff);
845 WriteU8 ((data >> 24) & 0xff);
848 Buffer::Iterator::WriteHtolsbU64 (uint64_t data)
850 WriteU8 ((data >> 0) & 0xff);
851 WriteU8 ((data >> 8) & 0xff);
852 WriteU8 ((data >> 16) & 0xff);
853 WriteU8 ((data >> 24) & 0xff);
854 WriteU8 ((data >> 32) & 0xff);
855 WriteU8 ((data >> 40) & 0xff);
856 WriteU8 ((data >> 48) & 0xff);
857 WriteU8 ((data >> 56) & 0xff);
861 Buffer::Iterator::WriteHtonU16 (uint16_t data)
863 WriteU8 ((data >> 8) & 0xff);
864 WriteU8 ((data >> 0) & 0xff);
867 Buffer::Iterator::WriteHtonU32 (uint32_t data)
869 WriteU8 ((data >> 24) & 0xff);
870 WriteU8 ((data >> 16) & 0xff);
871 WriteU8 ((data >> 8) & 0xff);
872 WriteU8 ((data >> 0) & 0xff);
875 Buffer::Iterator::WriteHtonU64 (uint64_t data)
877 WriteU8 ((data >> 56) & 0xff);
878 WriteU8 ((data >> 48) & 0xff);
879 WriteU8 ((data >> 40) & 0xff);
880 WriteU8 ((data >> 32) & 0xff);
881 WriteU8 ((data >> 24) & 0xff);
882 WriteU8 ((data >> 16) & 0xff);
883 WriteU8 ((data >> 8) & 0xff);
884 WriteU8 ((data >> 0) & 0xff);
887 Buffer::Iterator::Write (uint8_t const*buffer, uint32_t size)
889 for (uint32_t i = 0; i < size; i++)
896 Buffer::Iterator::ReadU16 (void)
898 uint8_t byte0 = ReadU8 ();
899 uint8_t byte1 = ReadU8 ();
900 uint16_t data = byte1;
907 Buffer::Iterator::ReadU32 (void)
909 uint8_t byte0 = ReadU8 ();
910 uint8_t byte1 = ReadU8 ();
911 uint8_t byte2 = ReadU8 ();
912 uint8_t byte3 = ReadU8 ();
913 uint32_t data = byte3;
923 Buffer::Iterator::ReadU64 (void)
925 uint8_t byte0 = ReadU8 ();
926 uint8_t byte1 = ReadU8 ();
927 uint8_t byte2 = ReadU8 ();
928 uint8_t byte3 = ReadU8 ();
929 uint8_t byte4 = ReadU8 ();
930 uint8_t byte5 = ReadU8 ();
931 uint8_t byte6 = ReadU8 ();
932 uint8_t byte7 = ReadU8 ();
933 uint64_t data = byte7;
952 Buffer::Iterator::ReadNtohU16 (void)
961 Buffer::Iterator::ReadNtohU32 (void)
974 Buffer::Iterator::ReadNtohU64 (void)
995 Buffer::Iterator::ReadLsbtohU16 (void)
997 uint8_t byte0 = ReadU8 ();
998 uint8_t byte1 = ReadU8 ();
999 uint16_t data = byte1;
1005 Buffer::Iterator::ReadLsbtohU32 (void)
1007 uint8_t byte0 = ReadU8 ();
1008 uint8_t byte1 = ReadU8 ();
1009 uint8_t byte2 = ReadU8 ();
1010 uint8_t byte3 = ReadU8 ();
1011 uint32_t data = byte3;
1021 Buffer::Iterator::ReadLsbtohU64 (void)
1023 uint8_t byte0 = ReadU8 ();
1024 uint8_t byte1 = ReadU8 ();
1025 uint8_t byte2 = ReadU8 ();
1026 uint8_t byte3 = ReadU8 ();
1027 uint8_t byte4 = ReadU8 ();
1028 uint8_t byte5 = ReadU8 ();
1029 uint8_t byte6 = ReadU8 ();
1030 uint8_t byte7 = ReadU8 ();
1031 uint64_t data = byte7;
1050 Buffer::Iterator::Read (uint8_t *buffer, uint32_t size)
1052 for (uint32_t i = 0; i < size; i++)
1054 buffer[i] = ReadU8 ();
1058 #ifndef BUFFER_USE_INLINE
1061 Buffer::Iterator::WriteU8 (uint8_t data)
1063 if (m_current < m_dataStart)
1065 // XXX trying to write outside of data area
1068 else if (m_current < m_zeroStart)
1070 m_data[m_current] = data;
1073 else if (m_current < m_zeroEnd)
1075 // XXX trying to write in zero area
1078 else if (m_current < m_dataEnd)
1080 m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
1085 // XXX trying to write outside of data area
1091 Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
1093 for (uint32_t i = 0; i < len; i++)
1100 Buffer::Iterator::ReadU8 (void)
1102 if (m_current < m_dataStart)
1104 // XXX trying to read from outside of data area
1107 else if (m_current < m_zeroStart)
1109 uint8_t data = m_data[m_current];
1113 else if (m_current < m_zeroEnd)
1118 else if (m_current < m_dataEnd)
1120 uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
1126 // XXX trying to read from outside of data area
1129 // to quiet compiler.
1133 #endif /* BUFFER_USE_INLINE */
1136 Buffer::Iterator::CalculateIpChecksum(uint16_t size)
1138 return CalculateIpChecksum(size, 0);
1142 Buffer::Iterator::CalculateIpChecksum(uint16_t size, uint32_t initialChecksum)
1144 /* see RFC 1071 to understand this code. */
1145 uint32_t sum = initialChecksum;
1147 for (int j = 0; j < size/2; j++)
1154 sum = (sum & 0xffff) + (sum >> 16);
1159 Buffer::Iterator::GetSize (void) const
1161 return m_dataEnd - m_dataStart;
1167 #ifdef RUN_SELF_TESTS
1169 #include "ns3/test.h"
1170 #include "ns3/random-variable.h"
1176 class BufferTest: public Test {
1178 bool EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[]);
1180 virtual bool RunTests (void);
1185 BufferTest::BufferTest ()
1186 : Test ("Buffer") {}
1189 BufferTest::EnsureWrittenBytes (Buffer b, uint32_t n, uint8_t array[])
1191 bool success = true;
1192 uint8_t *expected = array;
1194 got = b.PeekData ();
1195 for (uint32_t j = 0; j < n; j++)
1197 if (got[j] != expected[j])
1204 Failure () << "Buffer -- ";
1205 Failure () << "expected: n=";
1206 Failure () << n << ", ";
1207 Failure ().setf (std::ios::hex, std::ios::basefield);
1208 for (uint32_t j = 0; j < n; j++)
1210 Failure () << (uint16_t)expected[j] << " ";
1212 Failure ().setf (std::ios::dec, std::ios::basefield);
1213 Failure () << "got: ";
1214 Failure ().setf (std::ios::hex, std::ios::basefield);
1215 for (uint32_t j = 0; j < n; j++)
1217 Failure () << (uint16_t)got[j] << " ";
1219 Failure () << std::endl;
1224 /* Note: works only when variadic macros are
1225 * available which is the case for gcc.
1228 #define ENSURE_WRITTEN_BYTES(buffer, n, ...) \
1230 uint8_t bytes[] = {__VA_ARGS__}; \
1231 if (!EnsureWrittenBytes (buffer, n , bytes)) \
1238 BufferTest::RunTests (void)
1243 buffer.AddAtStart (6);
1244 i = buffer.Begin ();
1246 ENSURE_WRITTEN_BYTES (buffer, 1, 0x66);
1247 i = buffer.Begin ();
1249 ENSURE_WRITTEN_BYTES (buffer, 1, 0x67);
1250 i.WriteHtonU16 (0x6568);
1251 i = buffer.Begin ();
1252 ENSURE_WRITTEN_BYTES (buffer, 3, 0x67, 0x65, 0x68);
1253 i.WriteHtonU16 (0x6369);
1254 ENSURE_WRITTEN_BYTES (buffer, 3, 0x63, 0x69, 0x68);
1255 i.WriteHtonU32 (0xdeadbeaf);
1256 ENSURE_WRITTEN_BYTES (buffer, 6, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
1257 buffer.AddAtStart (2);
1258 i = buffer.Begin ();
1260 ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf);
1261 buffer.AddAtEnd (2);
1262 i = buffer.Begin ();
1265 ENSURE_WRITTEN_BYTES (buffer, 10, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
1266 buffer.RemoveAtStart (3);
1267 i = buffer.Begin ();
1268 ENSURE_WRITTEN_BYTES (buffer, 7, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
1269 buffer.RemoveAtEnd (4);
1270 i = buffer.Begin ();
1271 ENSURE_WRITTEN_BYTES (buffer, 3, 0x69, 0xde, 0xad);
1272 buffer.AddAtStart (1);
1273 i = buffer.Begin ();
1275 ENSURE_WRITTEN_BYTES (buffer, 4, 0xff, 0x69, 0xde, 0xad);
1276 buffer.AddAtEnd (1);
1277 i = buffer.Begin ();
1281 uint16_t saved = i.ReadU16 ();
1283 i.WriteHtonU16 (0xff00);
1285 if (i.ReadNtohU16 () != 0xff00)
1291 ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
1293 ENSURE_WRITTEN_BYTES (o, 5, 0xff, 0x69, 0xde, 0xad, 0xff);
1297 ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
1298 buffer.AddAtStart (2);
1299 i = buffer.Begin ();
1302 ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff);
1303 ENSURE_WRITTEN_BYTES (buffer, 7, 0xfd, 0xfd, 0xff, 0x69, 0xde, 0xad, 0xff);
1305 // test 64-bit read/write
1307 buff64.AddAtStart(8);
1309 i.WriteU64 (0x0123456789ABCDEFllu);
1310 ENSURE_WRITTEN_BYTES (buff64, 8, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01);
1312 if (i.ReadLsbtohU64() != 0x0123456789abcdefllu)
1317 i.WriteHtolsbU64 (0x0123456789ABCDEFllu);
1318 ENSURE_WRITTEN_BYTES (buff64, 8, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01);
1320 if (i.ReadLsbtohU64() != 0x0123456789abcdefllu)
1325 i.WriteHtonU64 (0x0123456789ABCDEFllu);
1326 ENSURE_WRITTEN_BYTES (buff64, 8, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef);
1328 if (i.ReadNtohU64() != 0x0123456789abcdefllu)
1333 // test self-assignment
1339 // test Remove start.
1340 buffer = Buffer (5);
1341 ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
1342 buffer.RemoveAtStart (1);
1343 ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
1344 buffer.AddAtStart (1);
1345 buffer.Begin ().WriteU8 (0xff);
1346 ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0, 0, 0, 0);
1347 buffer.RemoveAtStart(3);
1348 ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
1349 buffer.AddAtStart (4);
1350 buffer.Begin ().WriteHtonU32 (0xdeadbeaf);
1351 ENSURE_WRITTEN_BYTES (buffer, 6, 0xde, 0xad, 0xbe, 0xaf, 0, 0);
1352 buffer.RemoveAtStart (2);
1353 ENSURE_WRITTEN_BYTES (buffer, 4, 0xbe, 0xaf, 0, 0);
1354 buffer.AddAtEnd (4);
1355 i = buffer.Begin ();
1357 i.WriteHtonU32 (0xdeadbeaf);
1358 ENSURE_WRITTEN_BYTES (buffer, 8, 0xbe, 0xaf, 0, 0, 0xde, 0xad, 0xbe, 0xaf);
1359 buffer.RemoveAtStart (5);
1360 ENSURE_WRITTEN_BYTES (buffer, 3, 0xad, 0xbe, 0xaf);
1362 buffer = Buffer (5);
1363 ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0);
1364 buffer.RemoveAtEnd (1);
1365 ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0);
1366 buffer.AddAtEnd (2);
1367 i = buffer.Begin ();
1371 ENSURE_WRITTEN_BYTES (buffer, 6, 0, 0, 0, 0, 0xab, 0xac);
1372 buffer.RemoveAtEnd (1);
1373 ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0xab);
1374 buffer.RemoveAtEnd (3);
1375 ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0);
1376 buffer.AddAtEnd (6);
1377 i = buffer.Begin ();
1385 ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
1386 buffer.AddAtStart (3);
1387 i = buffer.Begin ();
1391 ENSURE_WRITTEN_BYTES (buffer, 11, 0x30, 0x31, 0x32, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb);
1392 buffer.RemoveAtEnd (9);
1393 ENSURE_WRITTEN_BYTES (buffer, 2, 0x30, 0x31);
1394 buffer = Buffer (3);
1395 buffer.AddAtEnd (2);
1396 i = buffer.Begin ();
1398 i.WriteHtonU16 (0xabcd);
1399 buffer.AddAtStart (1);
1400 buffer.Begin ().WriteU8 (0x21);
1401 ENSURE_WRITTEN_BYTES (buffer, 6, 0x21, 0, 0, 0, 0xab, 0xcd);
1402 buffer.RemoveAtEnd (8);
1403 if (buffer.GetSize () != 0)
1408 buffer = Buffer (6);
1409 buffer.AddAtStart (9);
1410 buffer.AddAtEnd (3);
1415 buffer = Buffer (6);
1416 buffer.AddAtStart (3);
1417 buffer.RemoveAtEnd (8);
1418 buffer.AddAtEnd (4);
1423 buffer = Buffer (1);
1424 buffer.AddAtEnd (100);
1430 buffer = Buffer (10);
1431 ENSURE_WRITTEN_BYTES (buffer, 10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
1432 buffer.Begin ().WriteU8 (1);
1433 ENSURE_WRITTEN_BYTES (buffer, 10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
1438 const uint32_t actualSize = 72602;
1439 const uint32_t chunkSize = 67624;
1440 UniformVariable bytesRng (0, 256);
1443 Buffer outputBuffer;
1445 inputBuffer.AddAtEnd (actualSize);
1447 Buffer::Iterator iter = inputBuffer.Begin ();
1448 for (uint32_t i = 0; i < actualSize; i++)
1449 iter.WriteU8 (static_cast<uint8_t> (bytesRng.GetValue ()));
1452 outputBuffer.AddAtEnd (chunkSize);
1453 Buffer::Iterator iter = outputBuffer.End ();
1454 iter.Prev (chunkSize);
1455 iter.Write (inputBuffer.PeekData (), chunkSize);
1457 NS_TEST_ASSERT (memcmp (inputBuffer.PeekData (), outputBuffer.PeekData (), chunkSize) == 0);
1460 buffer = Buffer (5);
1461 buffer.AddAtEnd (2);
1466 ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
1467 Buffer frag0 = buffer.CreateFragment (0, 2);
1468 ENSURE_WRITTEN_BYTES (frag0, 2, 0x00, 0x00);
1469 Buffer frag1 = buffer.CreateFragment (2, 5);
1470 ENSURE_WRITTEN_BYTES (frag1, 5, 0x00, 0x00, 0x00, 0x00, 0x66);
1471 frag0.AddAtEnd (frag1);
1472 ENSURE_WRITTEN_BYTES (buffer, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
1473 ENSURE_WRITTEN_BYTES (frag0, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66);
1480 static BufferTest gBufferTest;
1484 #endif /* RUN_SELF_TESTS */