INET Framework for OMNeT++/OMNEST
inet::ChunkBuffer Class Reference

This class provides basic functionality for merging large data chunks from out of order smaller data chunks. More...

#include <ChunkBuffer.h>

Inheritance diagram for inet::ChunkBuffer:
inet::ReassemblyBuffer inet::ReorderBuffer

Classes

class  Region
 

Public Member Functions

Constructors, destructors and duplication related functions
 ChunkBuffer (const char *name=nullptr)
 
 ChunkBuffer (const ChunkBuffer &other)
 
virtual ChunkBufferdup () const override
 
Content querying functions
bool isEmpty () const
 Returns true if the buffer is completely empty. More...
 
int getNumRegions () const
 Returns the number non-overlapping, non-connecting but continuous regions. More...
 
b getRegionLength (int index) const
 Returns the length of the given region. More...
 
b getRegionStartOffset (int index) const
 Returns the start offset of the given region. More...
 
b getRegionEndOffset (int index) const
 Returns the end offset of the given region. More...
 
const Ptr< const Chunk > & getRegionData (int index) const
 Returns the data of the given region in its current representation. More...
 
void replace (b offset, const Ptr< const Chunk > &chunk)
 Replaces the stored data at the provided offset with the data in the chunk. More...
 
void clear (b offset, b length)
 Erases the stored data at the provided offset and length. More...
 
void clear ()
 Erases all of the stored data. More...
 
virtual std::string str () const override
 Returns a human readable string representation. More...
 

Protected Member Functions

RegiongetRegion (int i) const
 
void eraseEmptyRegions (std::vector< Region >::iterator begin, std::vector< Region >::iterator end)
 
void sliceRegions (Region &newRegion)
 
void mergeRegions (Region &previousRegion, Region &nextRegion)
 

Protected Attributes

std::vector< Regionregions
 The list of non-overlapping, non-connecting but continuous regions. More...
 

Friends

class ChunkBufferDescriptor
 
class ChunkBuffer__RegionDescriptor
 

Detailed Description

This class provides basic functionality for merging large data chunks from out of order smaller data chunks.

Internally, buffers stores the data in different kind of chunks. See the Chunk class and its subclasses for details. All chunks are immutable in a buffer. Chunks are automatically merged as they are replaced in the buffer, and they are also shared among buffers when duplicating.

In general, this class supports the following operations:

  • push at the tail and pop at the head
  • query the length
  • serialize to and deserialize from a sequence of bits or bytes
  • copy to a new queue
  • convert to a human readable string

Constructor & Destructor Documentation

◆ ChunkBuffer() [1/2]

inet::ChunkBuffer::ChunkBuffer ( const char *  name = nullptr)
17  :
18  cNamedObject(name)
19 {
20 }

◆ ChunkBuffer() [2/2]

inet::ChunkBuffer::ChunkBuffer ( const ChunkBuffer other)
22  :
23  cNamedObject(other),
24  regions(other.regions)
25 {
26 }

Member Function Documentation

◆ clear() [1/2]

void inet::ChunkBuffer::clear ( )
inline

Erases all of the stored data.

133 { regions.clear(); }

Referenced by inet::ReorderBuffer::popAvailableData().

◆ clear() [2/2]

void inet::ChunkBuffer::clear ( b  offset,
b  length 
)

Erases the stored data at the provided offset and length.

150 {
151  CHUNK_CHECK_USAGE(offset >= b(0), "offset is invalid");
152  CHUNK_CHECK_USAGE(length >= b(0), "length is invalid");
153  for (auto it = regions.begin(); it != regions.end(); it++) {
154  auto region = *it;
155  if (region.offset == offset && region.data->getChunkLength() == length) {
156  regions.erase(it);
157  return;
158  }
159  }
160  auto data = makeShared<ByteCountChunk>(length);
161  Region clearedRegion(offset, data);
162  sliceRegions(clearedRegion);
163 }

Referenced by inet::tcp::TcpReceiveQueue::init().

◆ dup()

virtual ChunkBuffer* inet::ChunkBuffer::dup ( ) const
inlineoverridevirtual
81 { return new ChunkBuffer(*this); }

◆ eraseEmptyRegions()

void inet::ChunkBuffer::eraseEmptyRegions ( std::vector< Region >::iterator  begin,
std::vector< Region >::iterator  end 
)
protected
29 {
30  // NOTE: begin and end are inclusive
31  CHUNK_CHECK_IMPLEMENTATION(begin != regions.end());
32  CHUNK_CHECK_IMPLEMENTATION(end != regions.end());
33  regions.erase(std::remove_if(begin, end + 1, [] (const Region& region) { return region.data == nullptr; }), end + 1);
34 }

Referenced by replace().

◆ getNumRegions()

◆ getRegion()

Region* inet::ChunkBuffer::getRegion ( int  i) const
inlineprotected
69 { return const_cast<Region *>(&regions[i]); } // only for class descriptor

◆ getRegionData()

const Ptr<const Chunk>& inet::ChunkBuffer::getRegionData ( int  index) const
inline

Returns the data of the given region in its current representation.

114 { return regions.at(index).data; }

◆ getRegionEndOffset()

b inet::ChunkBuffer::getRegionEndOffset ( int  index) const
inline

Returns the end offset of the given region.

109 { return regions.at(index).getEndOffset(); }

Referenced by inet::tcp::TcpReceiveQueue::getLE(), inet::tcp::TcpReceiveQueue::getRE(), inet::tcp::TcpReceiveQueue::insertBytesFromSegment(), and inet::tcp::TcpReceiveQueue::str().

◆ getRegionLength()

b inet::ChunkBuffer::getRegionLength ( int  index) const
inline

Returns the length of the given region.

99 { return regions.at(index).data->getChunkLength(); }

Referenced by inet::tcp::TcpReceiveQueue::getAmountOfBufferedBytes(), and inet::tcp::TcpReceiveQueue::insertBytesFromSegment().

◆ getRegionStartOffset()

b inet::ChunkBuffer::getRegionStartOffset ( int  index) const
inline

◆ isEmpty()

bool inet::ChunkBuffer::isEmpty ( ) const
inline

Returns true if the buffer is completely empty.

89 { return regions.empty(); }

Referenced by inet::tcp::TcpReceiveQueue::extractBytesUpTo(), and inet::tcp::TcpReceiveQueue::insertBytesFromSegment().

◆ mergeRegions()

void inet::ChunkBuffer::mergeRegions ( Region previousRegion,
Region nextRegion 
)
protected
81 {
82  CHUNK_CHECK_IMPLEMENTATION(previousRegion.data != nullptr);
83  CHUNK_CHECK_IMPLEMENTATION(nextRegion.data != nullptr);
84  if (previousRegion.getEndOffset() == nextRegion.getStartOffset()) {
85  // consecutive regions
86  if (previousRegion.data->canInsertAtBack(nextRegion.data)) {
87  // merge into previous
88  const auto& newData = makeExclusivelyOwnedMutableChunk(previousRegion.data);
89  newData->insertAtBack(nextRegion.data);
90  newData->markImmutable();
91  previousRegion.data = newData->simplify();
92  nextRegion.data = nullptr;
93  }
94  else if (nextRegion.data->canInsertAtFront(previousRegion.data)) {
95  // merge into next
96  const auto& newData = makeExclusivelyOwnedMutableChunk(nextRegion.data);
97  newData->insertAtFront(previousRegion.data);
98  newData->markImmutable();
99  nextRegion.data = newData->simplify();
100  nextRegion.offset = previousRegion.offset;
101  previousRegion.data = nullptr;
102  }
103  else {
104  // merge as a sequence
105  auto sequenceChunk = makeShared<SequenceChunk>();
106  sequenceChunk->insertAtBack(previousRegion.data);
107  sequenceChunk->insertAtBack(nextRegion.data);
108  sequenceChunk->markImmutable();
109  previousRegion.data = sequenceChunk;
110  nextRegion.data = nullptr;
111  }
112  }
113 }

Referenced by replace().

◆ replace()

void inet::ChunkBuffer::replace ( b  offset,
const Ptr< const Chunk > &  chunk 
)

Replaces the stored data at the provided offset with the data in the chunk.

Already existing data gets overwritten, and connecting data gets merged with the provided chunk.

116 {
117  CHUNK_CHECK_USAGE(offset >= b(0), "offset is invalid");
118  CHUNK_CHECK_USAGE(chunk != nullptr, "chunk is nullptr");
119  CHUNK_CHECK_USAGE(chunk->getChunkLength() > b(0), "chunk is empty");
120  constPtrCast<Chunk>(chunk)->markImmutable();
121  Region newRegion(offset, chunk);
122  sliceRegions(newRegion);
123  if (regions.empty())
124  regions.push_back(newRegion);
125  else if (regions.back().getEndOffset() <= offset) {
126  regions.push_back(newRegion);
127  mergeRegions(regions[regions.size() - 2], regions[regions.size() - 1]);
128  eraseEmptyRegions(regions.end() - 2, regions.end() - 1);
129  }
130  else if (offset + chunk->getChunkLength() <= regions.front().getStartOffset()) {
131  regions.insert(regions.begin(), newRegion);
132  mergeRegions(regions[0], regions[1]);
133  eraseEmptyRegions(regions.begin(), regions.begin() + 1);
134  }
135  else {
136  auto it = std::upper_bound(regions.begin(), regions.end(), newRegion, Region::compareStartOffset);
137  it = regions.insert(it, newRegion);
138  auto& previousRegion = *(it - 1);
139  auto& region = *it;
140  auto& nextRegion = *(it + 1);
141  if (it != regions.begin())
142  mergeRegions(previousRegion, region);
143  if (it + 1 != regions.end())
144  mergeRegions(region.data != nullptr ? region : previousRegion, nextRegion);
145  eraseEmptyRegions(it != regions.begin() ? it - 1 : it, it + 1 != regions.end() ? it + 1 : it);
146  }
147 }

Referenced by inet::Ipv4FragBuf::addFragment(), inet::Ipv6FragBuf::addFragment(), and inet::tcp::TcpReceiveQueue::insertBytesFromSegment().

◆ sliceRegions()

void inet::ChunkBuffer::sliceRegions ( Region newRegion)
protected
37 {
38  if (!regions.empty()) {
39  auto lowerit = std::lower_bound(regions.begin(), regions.end(), newRegion, Region::compareStartOffset);
40  if (lowerit != regions.begin())
41  lowerit--;
42  auto upperit = std::upper_bound(regions.begin(), regions.end(), newRegion, Region::compareEndOffset);
43  if (upperit != regions.end())
44  upperit++;
45  for (auto it = lowerit; it < upperit; it++) {
46  auto& oldRegion = *it;
47  if (newRegion.getEndOffset() <= oldRegion.getStartOffset() || oldRegion.getEndOffset() <= newRegion.getStartOffset())
48  // no intersection
49  continue;
50  else if (newRegion.getStartOffset() <= oldRegion.getStartOffset() && oldRegion.getEndOffset() <= newRegion.getEndOffset()) {
51  // new totally covers old
52  oldRegion.data = nullptr;
53  regions.erase(it--);
54  upperit--;
55  }
56  else if (oldRegion.getStartOffset() < newRegion.getStartOffset() && newRegion.getEndOffset() < oldRegion.getEndOffset()) {
57  // new splits old into two parts
58  Region previousRegion(oldRegion.getStartOffset(), oldRegion.data->peek(b(0), newRegion.getStartOffset() - oldRegion.getStartOffset()));
59  Region nextRegion(newRegion.getEndOffset(), oldRegion.data->peek(newRegion.getEndOffset() - oldRegion.getStartOffset(), oldRegion.getEndOffset() - newRegion.getEndOffset()));
60  oldRegion.offset = nextRegion.offset;
61  oldRegion.data = nextRegion.data;
62  regions.insert(it, previousRegion);
63  return;
64  }
65  else if (oldRegion.getEndOffset() <= newRegion.getEndOffset()) {
66  // new cuts end of old
67  oldRegion.data = oldRegion.data->peek(b(0), newRegion.getStartOffset() - oldRegion.getStartOffset());
68  }
69  else if (newRegion.getStartOffset() <= oldRegion.getStartOffset()) {
70  // new cuts beginning of old
71  oldRegion.data = oldRegion.data->peek(newRegion.getEndOffset() - oldRegion.getStartOffset(), oldRegion.getEndOffset() - newRegion.getEndOffset());
72  oldRegion.offset = newRegion.getEndOffset();
73  }
74  else
76  }
77  }
78 }

Referenced by clear(), and replace().

◆ str()

std::string inet::ChunkBuffer::str ( ) const
overridevirtual

Returns a human readable string representation.

166 {
167  std::ostringstream os;
168  os << "ChunkBuffer, regions = {";
169  bool first = true;
170  for (auto& region : regions) {
171  if (!first)
172  os << " | ";
173  else
174  first = false;
175  os << EV_FIELD(offset, region.offset) << ", chunk = ";
176  if (region.data == nullptr)
177  os << "<nullptr>";
178  else
179  os << region.data;
180  }
181  os << "}";
182  return os.str();
183 }

Referenced by inet::operator<<().

Friends And Related Function Documentation

◆ ChunkBuffer__RegionDescriptor

friend class ChunkBuffer__RegionDescriptor
friend

◆ ChunkBufferDescriptor

friend class ChunkBufferDescriptor
friend

Member Data Documentation

◆ regions

std::vector<Region> inet::ChunkBuffer::regions
protected

The list of non-overlapping, non-connecting but continuous regions.

Referenced by clear(), eraseEmptyRegions(), inet::ReorderBuffer::getAvailableDataLength(), inet::ReorderBuffer::popAvailableData(), replace(), sliceRegions(), and str().


The documentation for this class was generated from the following files:
inet::ChunkBuffer::sliceRegions
void sliceRegions(Region &newRegion)
Definition: ChunkBuffer.cc:36
CHUNK_CHECK_IMPLEMENTATION
#define CHUNK_CHECK_IMPLEMENTATION(condition)
Definition: Chunk.h:29
inet::ChunkBuffer::mergeRegions
void mergeRegions(Region &previousRegion, Region &nextRegion)
Definition: ChunkBuffer.cc:80
inet::ChunkBuffer::ChunkBuffer
ChunkBuffer(const char *name=nullptr)
Definition: ChunkBuffer.cc:17
inet::makeExclusivelyOwnedMutableChunk
const Ptr< T > makeExclusivelyOwnedMutableChunk(const Ptr< const T > &chunk)
Definition: Chunk.h:860
inet::ChunkBuffer::Region::compareStartOffset
static bool compareStartOffset(const Region &a, const Region &b)
Definition: ChunkBuffer.h:58
CHUNK_CHECK_USAGE
#define CHUNK_CHECK_USAGE(condition, format,...)
Definition: Chunk.h:42
inet::ChunkBuffer::Region::compareEndOffset
static bool compareEndOffset(const Region &a, const Region &b)
Definition: ChunkBuffer.h:59
EV_FIELD
#define EV_FIELD(...)
Definition: INETDefs.h:112
inet::units::values::b
value< int64_t, units::b > b
Definition: Units.h:1241
inet::ChunkBuffer::eraseEmptyRegions
void eraseEmptyRegions(std::vector< Region >::iterator begin, std::vector< Region >::iterator end)
Definition: ChunkBuffer.cc:28
inet::ChunkBuffer::regions
std::vector< Region > regions
The list of non-overlapping, non-connecting but continuous regions.
Definition: ChunkBuffer.h:66