任务回顾
在lab1中要实现一个Reassembler类,基于Lab0的字节流类实现,要实现如下功能:
- 包含一个字节流类和读写接口
- 提供一个insert方法
-
接收3个数据:字节索引(index),字符串(data),结束标志(is_last_substring)
- 每次收到的数据顺序混乱
- 可能受到有重叠的数据
- 每次收到的字符串连续
-
insert方法将输入的子串进行排序和去重等操作以还原为原始数据,并按顺序写入字节流中。全部写完后关闭写接口
-
- 知道 next_index 下一个期望写入流的自字节索引
- 缓存适合流的可用容量但尚不能写入的字节
- 丢弃超出流可用容量的字节
难点在于对随机收到的字节数据自动复原
思路
首先不管怎么样,一定要维护一个next_index表示写一个希望写入的字节索引。
然后写入采用lazzy的方法,每次接受新的子串后写入最大能写入的字节。这里要注意如果缓存的字节大小大于可写入大小,且如果这是最后一个子串,将写不完,
一开始想用想维护一个按头索引顺序排列的子串数组,每个元素是一个子串。然后用二分查找插入新来的子串,每次插入时和前后的子串比较,去掉重复的部分。
这样可以用O(logn)的复杂度找到插入点,可是数组的插入复杂度为O(n)
考虑使用C++的数据结构map,基于红黑树实现,内部自动排序,插入、查找的复杂度为O(logn)
然后终止条件设置为写入字节数等于总共字节数,后者在收到is_last_substring后计算得到
代码
void Reassembler::insert( uint64_t first_index, string data, bool is_last_substring )
{
if ( is_last_substring ) {
last_index_ = first_index + data.size();
}
const uint64_t max_index = next_index_ + output_.writer().available_capacity() - 1+100;
if ( first_index > max_index ) {
return;
} else if ( first_index + data.size() < next_index_ ) {
return;
}
if ( first_index < next_index_ ) {
data = data.substr( next_index_ - first_index );
first_index = next_index_;
}
if ( first_index + data.size() > max_index + 1 ) {
data = data.substr( 0, max_index - first_index + 1 );
}
if (buffer_.find( first_index ) != buffer_.end()){
if (buffer_[first_index].size() >= data.size()){
return;
}
}
if (!data.empty()){
buffer_[first_index] = data;
// 去重
bool live_flag = true;
auto n_t = buffer_.find( first_index );
if (n_t-- != buffer_.begin()){
if (n_t->first + n_t->second.size() >= first_index+ buffer_[first_index].size()){
buffer_.erase( ++n_t );
live_flag = false;
} else if (n_t->first + n_t->second.size() > first_index){
n_t->second.erase( first_index - n_t->first, n_t->second.size() - first_index +n_t->first);
}
}
if(live_flag) {
n_t = buffer_.find( first_index );
n_t++;
while ( n_t != buffer_.end()){
if (n_t->first < first_index + buffer_[first_index].size()){
if (n_t->first + n_t->second.size() <= first_index + buffer_[first_index].size()){
buffer_.erase( n_t );
} else{
buffer_[first_index].erase( n_t->first - first_index, buffer_[first_index].size() - n_t->first +first_index);
}
n_t = buffer_.find( first_index );
n_t++;
} else{
break;
}
}
}
}
while ( buffer_.find( next_index_ ) != buffer_.end() ) {
auto it = buffer_.find( next_index_ );
output_.writer().push( it->second );
next_index_ += it->second.size();
buffer_.erase( it );
}
if ( next_index_ == last_index_ ) {
output_.writer().close();
}
}