总结

把总结放在开头,方便回顾,下面是要点

  • 容量要求:已缓存但未加入流中的字节数+流中的字节数<=capacity
  • 使用1个数据结构保存“已缓存但未加入流中的字节数”,我用的是Map
    • value是一个string,表示一段数据
    • key是一个size_t,表示这段数据的第一个字节在字节流中的序号
    • 这个数据结构实际上处理的是区间合并问题
  • 使用_next_index表示还未加入流中的第一个字节序号,那么总的窗口就是[_next_index, _next_index+capacity)
    • Map的窗口就是[_next_index, _next_index+capacity-ByteStream.size())
    • 或者也可以表示成[_next_index, _next_index+ByteStream.remaining_capacity())
    • Map中保存的是在这个大区间内的不相交的若干个子区间
  • push_string传进来的data,需要和Map的窗口取交集,记为[L, R),这部分数据是实际上保留下来的,准备加入Map乃至加入流中的数据
  • 找出Map中所有与[L, R)相交的区间
    • 若找到多个这样的区间,则实际起作用的最多是第一个和最后一个区间,中间的区间一定都是[L, R)的子区间
    • 把第一个区间、最后一个区间和[L, R)按照序号合并成1个字符串,其区间记为[union_l, union_r)
    • 若Map中没有区间和[L, R)相交,则[L, R)==[union_l, union_r)
  • 从Map中删除所有与[L, R)相交的区间
  • 将[union_l, union_r)加入Map中
  • 最后按序号从小到大的顺序遍历Map,检查区间的左端点是否与_next_index相等
    • 若相等,则将这个区间加入流中
    • 每次遍历,都要更新_next_index,因为后面的区间虽然不相交,但是可能是连着的,也要处理
  • 当然别忘了处理eof
    • 如果带有eof的字节被加入流中,则调用流的end_input()
  • 代码中使用的序号变量类型是size_t,在64位系统下,这个类型实际上是64位无符号整数

    第一阶段

    思路

  • 保存乱序数据的结构:Map

    • 按照Key的Index从小到大排序,C++的map默认情况下应该就会这样排序
  • 问题:如果当前push了一个string,只能存下这个string的一部分数据怎么办?

    • 方案一:整个数据不要了,等到它下次push再尝试
      • 问题:如果capacity很小,数据很大,那么这个数据永远都放不进来
    • 方案二:存一部分数据进去,那么传进来的string会被拆开
  • Map中缓存的数据应该是有限的

    • next_index+capacity-stream.size()是上界,开区间
    • Map中序号最小和序号最大的这两份数据,都可能只是传进来的string的一部分
      • ①序号最小的数据,如果Map中只保存了一部分,说明它前面的那部分已经被加入到流中了
      • ②序号最大的数据,如果Map中只保存了一部分,说明在它保存进来的那个时刻,达到了capacity指定的上限
      • ②是①的因
  • 设想这样一种情况,capacity的值比较小,只有100,整个字节流只包含1个string,这个string的大小为1000
    • 那么Map中从头到尾放入的数据最多只有1份,且每次只能放入这个string的一部分

算法步骤

  1. 传入一个string,比较它的区间端点[index, index+string.size())和Map的区间端点[next_index, next_index+capacity-stream.size())的大小关系
    1. 不相交的部分丢弃,相交的部分添加到Map中
    2. 实际上,ByteStream的remaining_capacity返回的就是capacity-stream.size()
    3. [a,b)和[c,d)相交的判断条件是b>c&&d>a;判断相交,则它们相交的区间是[max(a,c), min(b,d))
  2. 尝试将相交部分放入Map中(实际上是一个区间问题)
    1. 如果序号Key已经存在,则更新Value(有可能保存更多的数据部分进来)
    2. 如果序号Key不存在,则put
  3. 比较next_index和Map中的最小序号
    1. 如果不相等,则没有数据可以提交到流中
    2. 如果相等,则从Map中取出从next_index开始的连续字节,放入流中
  • 问题:第三步中,如果从Map中取出数据,Map有空余容量了,还需要回到第一步吗?
    • 不需要!时刻牢记,Map的容量和Stream的容量是合在一起的,在当前时刻,Stream里的数据肯定不会有人拿走(CS144明确说了不涉及多线程,即使涉及多线程,也是加锁的,别人不可能再同一时刻从Stream里取走数据)
    • Map有空余容量不代表整体有空余容量

如何处理eof?

  • 我设置了一个size_t类型的变量eof_index,初始值为size_t的最大值(字节流会超过size_t的最大值吗)
  • 如果收到了带eof=true的string,则更新eof_index
  • 如果Map已空,且eof_index不是size_t的最大值(已经被设置),且字节序号已经达到了eof_index,则调用ByteStream的end_input

代码

  1. #ifndef SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  2. #define SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  3. #include "byte_stream.hh"
  4. #include <cstdint>
  5. #include <string>
  6. #include <map>
  7. //! \brief A class that assembles a series of excerpts from a byte stream (possibly out of order,
  8. //! possibly overlapping) into an in-order byte stream.
  9. class StreamReassembler {
  10. private:
  11. // Your code here -- add private members as necessary.
  12. size_t _next_index;
  13. size_t _eof_index;
  14. std::map<size_t, std::string> _unassembled_strings;
  15. size_t _unassembled_bytes;
  16. ByteStream _output; //!< The reassembled in-order byte stream
  17. size_t _capacity; //!< The maximum number of bytes
  18. public:
  19. //! \brief Construct a `StreamReassembler` that will store up to `capacity` bytes.
  20. //! \note This capacity limits both the bytes that have been reassembled,
  21. //! and those that have not yet been reassembled.
  22. StreamReassembler(const size_t capacity);
  23. //! \brief Receive a substring and write any newly contiguous bytes into the stream.
  24. //!
  25. //! The StreamReassembler will stay within the memory limits of the `capacity`.
  26. //! Bytes that would exceed the capacity are silently discarded.
  27. //!
  28. //! \param data the substring
  29. //! \param index indicates the index (place in sequence) of the first byte in `data`
  30. //! \param eof the last byte of `data` will be the last byte in the entire stream
  31. void push_substring(const std::string &data, const uint64_t index, const bool eof);
  32. //! \name Access the reassembled byte stream
  33. //!@{
  34. const ByteStream &stream_out() const { return _output; }
  35. ByteStream &stream_out() { return _output; }
  36. //!@}
  37. //! The number of bytes in the substrings stored but not yet reassembled
  38. //!
  39. //! \note If the byte at a particular index has been pushed more than once, it
  40. //! should only be counted once for the purpose of this function.
  41. size_t unassembled_bytes() const;
  42. //! \brief Is the internal state empty (other than the output stream)?
  43. //! \returns `true` if no substrings are waiting to be assembled
  44. bool empty() const;
  45. };
  46. #endif // SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  47. #include "stream_reassembler.hh"
  48. #include <cmath>
  49. // Dummy implementation of a stream reassembler.
  50. // For Lab 1, please replace with a real implementation that passes the
  51. // automated checks run by `make check_lab1`.
  52. // You will need to add private members to the class declaration in `stream_reassembler.hh`
  53. template <typename... Targs>
  54. void DUMMY_CODE(Targs &&... /* unused */) {}
  55. using namespace std;
  56. StreamReassembler::StreamReassembler(const size_t capacity)
  57. : _next_index(0), _eof_index(unsigned(-1)), _unassembled_strings(), _unassembled_bytes(0),
  58. _output(capacity), _capacity(capacity) {
  59. }
  60. //! \details This function accepts a substring (aka a segment) of bytes,
  61. //! possibly out-of-order, from the logical stream, and assembles any newly
  62. //! contiguous substrings and writes them into the output stream in order.
  63. void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof) {
  64. if (eof) {
  65. _eof_index = index+data.size();
  66. }
  67. // [index, index+string.size())
  68. // [_next_index, _next_index+capacity-stream.size())=[_next_index, _next_index+_output.remaining_capacity())
  69. if (index+data.size()>_next_index&&_next_index+_output.remaining_capacity()>index) { // 有相交的部分,或者说有可以缓存的数据
  70. size_t L = std::max(index, _next_index);
  71. size_t R = std::min(index+data.size(), _next_index+_output.remaining_capacity());
  72. auto iter = _unassembled_strings.begin();
  73. while (iter!=_unassembled_strings.end()) {
  74. if (iter->first==L) {
  75. break;
  76. }
  77. iter++; // 这句话一开始漏了
  78. }
  79. if (iter==_unassembled_strings.end()) { // 没有找到,则新建
  80. _unassembled_strings.insert(map<size_t, std::string>::value_type(L, data.substr(L-index, R-L)));
  81. } else { // 找到了,则更新
  82. iter->second=data.substr(L-index, R-L);
  83. }
  84. }
  85. // 接下来比较_next_index和Map中的最小序号
  86. int toDeleteCount=0;
  87. auto iter = _unassembled_strings.begin();
  88. while (iter!=_unassembled_strings.end()) {
  89. if (iter->first!=_next_index) {
  90. break;
  91. }
  92. toDeleteCount++;
  93. // 一定可以全部写入吧???因为前面计算过了
  94. _output.write(iter->second);
  95. // string toAddStr = iter->second;
  96. // size_t added = 0;
  97. // while (added<iter->second.size()) {
  98. // added+=_output.write(iter->second.substr(added, iter->second.size()-added));
  99. // }
  100. _next_index+=iter->second.size();
  101. }
  102. iter = _unassembled_strings.begin();
  103. for (int i=0; i<toDeleteCount; i++) {
  104. _unassembled_strings.erase(iter++);
  105. }
  106. if (_unassembled_strings.size()==0&&_next_index==_eof_index) {
  107. _output.end_input();
  108. }
  109. }
  110. // 返回已经缓存,但未组装到字节流中的字节个数
  111. size_t StreamReassembler::unassembled_bytes() const {
  112. size_t res=0;
  113. auto iter = _unassembled_strings.begin();
  114. while (iter!=_unassembled_strings.end()) {
  115. res+=iter->second.size();
  116. }
  117. return res;
  118. }
  119. // unassembled_bytes()==0
  120. bool StreamReassembler::empty() const {
  121. return unassembled_bytes()==0;
  122. }

测试结果

  • 过了一半的样例

image.png
后来发现遍历Map忘记iter++,但是加上去之后测试结果没变

第二阶段

思路

  • 保存乱序数据的结构:Map

    • 按照Key的Index从小到大排序,C++的map默认情况下应该就会这样排序
  • 问题:如果当前push了一个string,只能存下这个string的一部分数据怎么办?

    • 存一部分数据进去,那么传进来的string会被拆开
  • Map中缓存的数据应该是有限的
    • next_index+capacity-stream.size()是上界,开区间
    • Map中序号最小和序号最大的这两份数据,都可能只是传进来的string的一部分
      • ①序号最小的数据,如果Map中只保存了一部分,说明它前面的那部分已经被加入到流中了
      • ②序号最大的数据,如果Map中只保存了一部分,说明在它保存进来的那个时刻,达到了capacity指定的上限
      • ②是①的因
  • 设想这样一种情况,capacity的值比较小,只有100,整个字节流只包含1个string,这个string的大小为1000
    • 那么Map中从头到尾放入的数据最多只有1份,且每次只能放入这个string的一部分

算法步骤

  1. 传入一个string,比较它的区间端点[index, index+string.size())和Map的区间端点[next_index, next_index+capacity-stream.size())的大小关系
    1. 不相交的部分丢弃,相交的部分添加到Map中
    2. 实际上,ByteStream的remaining_capacity返回的就是capacity-stream.size()
    3. [a,b)和[c,d)相交的判断条件是b>c&&d>a;判断相交,则它们相交的区间是[max(a,c), min(b,d))
    4. 记这里计算得到的待加入Map的字节流区间为[L, R)
  2. 尝试将[x, y)放入Map中(实际上是一个区间问题)
    1. 按顺序遍历Map,从中找出与[x, y)相交的区间,这些区间需要被标记删除
    2. 记这些相交的区间为[a0, b0),[a2, b2),……, [an, bn)
    3. 那么最终合并后的结果为[a0, b0)的部分+[L, R)+[an, bn)的部分
      1. 如果没有找到相交的区间,则这里得到的结果就是[L, R)
      2. 如果相交的区间只有一个,则注意它是[a0, b0)还是 [an, bn),也就是区分在[L, R)的左侧还是右侧
    4. 从Map中删除这些区间
    5. 将合并后的结果加入Map中
  3. 比较next_index和Map中的最小序号
    1. 如果不相等,则没有数据可以提交到流中
    2. 如果相等,则从Map中取出从next_index开始的连续字节,放入流中(就是key最小的那个key-value对)
  • 问题:第三步中,如果从Map中取出数据,Map有空余容量了,还需要回到第一步吗?
    • 不需要!时刻牢记,Map的容量和Stream的容量是合在一起的,在当前时刻,Stream里的数据肯定不会有人拿走(CS144明确说了不涉及多线程,即使涉及多线程,也是加锁的,别人不可能再同一时刻从Stream里取走数据)
    • Map有空余容量不代表整体有空余容量

如何处理eof?

  • 我设置了一个size_t类型的变量eof_index,初始值为size_t的最大值(字节流会超过size_t的最大值吗)
  • 如果收到了带eof=true的string,则更新eof_index
  • 如果Map已空,且eof_index不是size_t的最大值(已经被设置),且字节序号已经达到了eof_index,则调用ByteStream的end_input

代码

发现byte_stream的read的bug

  1. std::string ByteStream::read(const size_t len) {
  2. string res;
  3. // 应该用一个变量保存一开始_data_q的大小
  4. size_t init_sz=_data_q.size();
  5. // i<_data_q.size()这么写不对!
  6. for (size_t i=0; i<len&&i<init_sz; i++) {
  7. res+=_data_q.front();
  8. _data_q.pop_front();
  9. _bytes_read++;
  10. }
  11. return res;
  12. }
  1. #ifndef SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  2. #define SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  3. #include "byte_stream.hh"
  4. #include <cstdint>
  5. #include <string>
  6. #include <map>
  7. #include <utility>
  8. //! \brief A class that assembles a series of excerpts from a byte stream (possibly out of order,
  9. //! possibly overlapping) into an in-order byte stream.
  10. class StreamReassembler {
  11. private:
  12. // Your code here -- add private members as necessary.
  13. size_t _next_index;
  14. size_t _eof_index;
  15. std::map<size_t, std::string> _unassembled_strings;
  16. size_t _unassembled_bytes;
  17. ByteStream _output; //!< The reassembled in-order byte stream
  18. size_t _capacity; //!< The maximum number of bytes
  19. public:
  20. //! \brief Construct a `StreamReassembler` that will store up to `capacity` bytes.
  21. //! \note This capacity limits both the bytes that have been reassembled,
  22. //! and those that have not yet been reassembled.
  23. StreamReassembler(const size_t capacity);
  24. //! \brief Receive a substring and write any newly contiguous bytes into the stream.
  25. //!
  26. //! The StreamReassembler will stay within the memory limits of the `capacity`.
  27. //! Bytes that would exceed the capacity are silently discarded.
  28. //!
  29. //! \param data the substring
  30. //! \param index indicates the index (place in sequence) of the first byte in `data`
  31. //! \param eof the last byte of `data` will be the last byte in the entire stream
  32. void push_substring(const std::string &data, const uint64_t index, const bool eof);
  33. //! \name Access the reassembled byte stream
  34. //!@{
  35. const ByteStream &stream_out() const { return _output; }
  36. ByteStream &stream_out() { return _output; }
  37. //!@}
  38. //! The number of bytes in the substrings stored but not yet reassembled
  39. //!
  40. //! \note If the byte at a particular index has been pushed more than once, it
  41. //! should only be counted once for the purpose of this function.
  42. size_t unassembled_bytes() const;
  43. //! \brief Is the internal state empty (other than the output stream)?
  44. //! \returns `true` if no substrings are waiting to be assembled
  45. bool empty() const;
  46. };
  47. #endif // SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  48. #include "stream_reassembler.hh"
  49. #include <cmath>
  50. #include <vector>
  51. #include <utility>
  52. #include <algorithm>
  53. #include <cstdio>
  54. #include <iostream>
  55. // Dummy implementation of a stream reassembler.
  56. // For Lab 1, please replace with a real implementation that passes the
  57. // automated checks run by `make check_lab1`.
  58. // You will need to add private members to the class declaration in `stream_reassembler.hh`
  59. template <typename... Targs>
  60. void DUMMY_CODE(Targs &&... /* unused */) {}
  61. using namespace std;
  62. StreamReassembler::StreamReassembler(const size_t capacity)
  63. : _next_index(0), _eof_index(unsigned(-1)), _unassembled_strings(), _unassembled_bytes(0),
  64. _output(capacity), _capacity(capacity) {
  65. }
  66. //! \details This function accepts a substring (aka a segment) of bytes,
  67. //! possibly out-of-order, from the logical stream, and assembles any newly
  68. //! contiguous substrings and writes them into the output stream in order.
  69. void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof) {
  70. if (eof) {
  71. _eof_index = index+data.size();
  72. }
  73. // [index, index+string.size())
  74. // [_next_index, _next_index+capacity-stream.size())=[_next_index, _next_index+_output.remaining_capacity())
  75. if (index+data.size()>_next_index&&_next_index+_output.remaining_capacity()>index) { // 有相交的部分,或者说有可以缓存的数据
  76. size_t L = std::max(index, _next_index);
  77. size_t R = std::min(index+data.size(), _next_index+_output.remaining_capacity());
  78. std::string true_data=data.substr(L-index, R-L);
  79. size_t x=0,y=0; // 表示了Map中待删除的区间
  80. size_t union_l=0, union_r=0;
  81. bool isOverlap=false;
  82. auto iter = _unassembled_strings.begin();
  83. size_t loc=0;
  84. std::pair<size_t, std::string> first_zone, last_zone;
  85. // std::vector<std::pair<size_t, std::string>> overlapped_strings;
  86. while (iter!=_unassembled_strings.end()) {
  87. // [L, R)和[iter->first, iter->first+iter.second.size())比较
  88. if (iter->first+iter->second.size()>L&&R>iter->first) { // 相交
  89. if (!isOverlap) {
  90. isOverlap = true;
  91. x=y=loc;
  92. first_zone=make_pair(iter->first, iter->second);
  93. union_l=std::min(L, iter->first);
  94. union_r=std::max(R, iter->first+iter->second.size());
  95. } else {
  96. y++;
  97. last_zone=make_pair(iter->first, iter->second);
  98. union_r=std::max(R, iter->first+iter->second.size());
  99. }
  100. } else {
  101. if (isOverlap) {
  102. break;
  103. }
  104. }
  105. loc++;
  106. iter++;
  107. }
  108. std::string union_string;
  109. if (isOverlap) {
  110. union_string=std::string(union_r-union_l, 'a');
  111. union_string.replace(L-union_l, R-L, true_data);
  112. union_string.replace(first_zone.first-union_l, first_zone.second.size(), first_zone.second);
  113. if (y>x) {
  114. union_string.replace(last_zone.first-union_l, last_zone.second.size(), last_zone.second);
  115. }
  116. } else {
  117. union_l=L;
  118. union_r=R;
  119. union_string=true_data;
  120. }
  121. if (isOverlap) {
  122. iter = _unassembled_strings.begin();
  123. loc=0;
  124. while (iter!=_unassembled_strings.end()) {
  125. if (loc>=x&&loc<=y) {
  126. _unassembled_strings.erase(iter++);
  127. } else {
  128. iter++;
  129. }
  130. loc++;
  131. }
  132. }
  133. std::cout<<"【"<<union_l<<","<<union_r<<"】"<<"******"<<std::endl;
  134. _unassembled_strings.insert(map<size_t, std::string>::value_type(union_l, union_string));
  135. }
  136. // 接下来比较_next_index和Map中的最小序号
  137. int toDeleteCount=0;
  138. auto iter = _unassembled_strings.begin();
  139. while (iter!=_unassembled_strings.end()) {
  140. if (iter->first!=_next_index) {
  141. break;
  142. }
  143. toDeleteCount++;
  144. // 一定可以全部写入吧???因为前面计算过了
  145. _output.write(iter->second);
  146. // string toAddStr = iter->second;
  147. // size_t added = 0;
  148. // while (added<iter->second.size()) {
  149. // added+=_output.write(iter->second.substr(added, iter->second.size()-added));
  150. // }
  151. _next_index+=iter->second.size();
  152. // bug1: 这里没有iter++
  153. }
  154. iter = _unassembled_strings.begin();
  155. for (int i=0; i<toDeleteCount; i++) {
  156. _unassembled_strings.erase(iter++);
  157. }
  158. if (_unassembled_strings.size()==0&&_next_index==_eof_index) {
  159. _output.end_input();
  160. std::cout<<"****** called _output.end_input(), unassembled_bytes(): "<<unassembled_bytes()<<std::endl;
  161. // std::cout<<"****** _output.eof(): "<<_output.eof()<<std::endl;
  162. // std::cout<<"****** empty(): "<<empty()<<std::endl;
  163. std::cout<<"****** _output.input_ended(): "<<_output.input_ended()<<std::endl;
  164. }
  165. std::cout<<"****** new _next_index: "<<_next_index<<std::endl;
  166. std::cout<<"****** remaining: "<<_output.remaining_capacity()<<std::endl;
  167. // std::cout<<"****** _output.read(): "<<_output.peek_output(8)<<std::endl;
  168. // std::cout<<"****** _output"
  169. }
  170. // 返回已经缓存,但未组装到字节流中的字节个数
  171. size_t StreamReassembler::unassembled_bytes() const {
  172. size_t res=0;
  173. // for (size_t i=0; i<_unassembled_strings.size(); i++) {
  174. // res+=_unassembled_strings[i].second.size();
  175. // }
  176. auto iter = _unassembled_strings.begin();
  177. while (iter!=_unassembled_strings.end()) {
  178. res+=iter->second.size();
  179. // bug2: 这里没有iter++;
  180. }
  181. return res;
  182. }
  183. // unassembled_bytes()==0
  184. bool StreamReassembler::empty() const {
  185. return unassembled_bytes()==0;
  186. }

测试结果

image.png
到这里git commit一下

两个bug都是没有写iter++


如果在第一阶段的代码中添加上述两处iter++,测试结果如下
image.png
其中1个样例如下
image.png
很显然是遗漏了1个字节

第三阶段(通过测试)

就是第二阶段的代码,加上两处iter++

  1. #ifndef SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  2. #define SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  3. #include "byte_stream.hh"
  4. #include <cstdint>
  5. #include <string>
  6. #include <map>
  7. #include <utility>
  8. //! \brief A class that assembles a series of excerpts from a byte stream (possibly out of order,
  9. //! possibly overlapping) into an in-order byte stream.
  10. class StreamReassembler {
  11. private:
  12. // Your code here -- add private members as necessary.
  13. size_t _next_index;
  14. size_t _eof_index;
  15. std::map<size_t, std::string> _unassembled_strings;
  16. size_t _unassembled_bytes;
  17. ByteStream _output; //!< The reassembled in-order byte stream
  18. size_t _capacity; //!< The maximum number of bytes
  19. public:
  20. //! \brief Construct a `StreamReassembler` that will store up to `capacity` bytes.
  21. //! \note This capacity limits both the bytes that have been reassembled,
  22. //! and those that have not yet been reassembled.
  23. StreamReassembler(const size_t capacity);
  24. //! \brief Receive a substring and write any newly contiguous bytes into the stream.
  25. //!
  26. //! The StreamReassembler will stay within the memory limits of the `capacity`.
  27. //! Bytes that would exceed the capacity are silently discarded.
  28. //!
  29. //! \param data the substring
  30. //! \param index indicates the index (place in sequence) of the first byte in `data`
  31. //! \param eof the last byte of `data` will be the last byte in the entire stream
  32. void push_substring(const std::string &data, const uint64_t index, const bool eof);
  33. //! \name Access the reassembled byte stream
  34. //!@{
  35. const ByteStream &stream_out() const { return _output; }
  36. ByteStream &stream_out() { return _output; }
  37. //!@}
  38. //! The number of bytes in the substrings stored but not yet reassembled
  39. //!
  40. //! \note If the byte at a particular index has been pushed more than once, it
  41. //! should only be counted once for the purpose of this function.
  42. size_t unassembled_bytes() const;
  43. //! \brief Is the internal state empty (other than the output stream)?
  44. //! \returns `true` if no substrings are waiting to be assembled
  45. bool empty() const;
  46. };
  47. #endif // SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  48. #include "stream_reassembler.hh"
  49. #include <cmath>
  50. #include <vector>
  51. #include <utility>
  52. #include <algorithm>
  53. #include <cstdio>
  54. #include <iostream>
  55. // Dummy implementation of a stream reassembler.
  56. // For Lab 1, please replace with a real implementation that passes the
  57. // automated checks run by `make check_lab1`.
  58. // You will need to add private members to the class declaration in `stream_reassembler.hh`
  59. template <typename... Targs>
  60. void DUMMY_CODE(Targs &&... /* unused */) {}
  61. using namespace std;
  62. StreamReassembler::StreamReassembler(const size_t capacity)
  63. : _next_index(0), _eof_index(unsigned(-1)), _unassembled_strings(), _unassembled_bytes(0),
  64. _output(capacity), _capacity(capacity) {
  65. }
  66. //! \details This function accepts a substring (aka a segment) of bytes,
  67. //! possibly out-of-order, from the logical stream, and assembles any newly
  68. //! contiguous substrings and writes them into the output stream in order.
  69. void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof) {
  70. if (eof) {
  71. _eof_index = index+data.size();
  72. }
  73. // [index, index+string.size())
  74. // [_next_index, _next_index+capacity-stream.size())=[_next_index, _next_index+_output.remaining_capacity())
  75. if (index+data.size()>_next_index&&_next_index+_output.remaining_capacity()>index) { // 有相交的部分,或者说有可以缓存的数据
  76. size_t L = std::max(index, _next_index);
  77. size_t R = std::min(index+data.size(), _next_index+_output.remaining_capacity());
  78. std::string true_data=data.substr(L-index, R-L);
  79. size_t x=0,y=0; // 表示了Map中待删除的区间
  80. size_t union_l=0, union_r=0;
  81. bool isOverlap=false;
  82. auto iter = _unassembled_strings.begin();
  83. size_t loc=0;
  84. std::pair<size_t, std::string> first_zone, last_zone;
  85. // std::vector<std::pair<size_t, std::string>> overlapped_strings;
  86. while (iter!=_unassembled_strings.end()) {
  87. // [L, R)和[iter->first, iter->first+iter.second.size())比较
  88. if (iter->first+iter->second.size()>L&&R>iter->first) { // 相交
  89. if (!isOverlap) {
  90. isOverlap = true;
  91. x=y=loc;
  92. first_zone=make_pair(iter->first, iter->second);
  93. union_l=std::min(L, iter->first);
  94. union_r=std::max(R, iter->first+iter->second.size());
  95. } else {
  96. y++;
  97. last_zone=make_pair(iter->first, iter->second);
  98. union_r=std::max(R, iter->first+iter->second.size());
  99. }
  100. } else {
  101. if (isOverlap) {
  102. break;
  103. }
  104. }
  105. loc++;
  106. iter++;
  107. }
  108. std::string union_string;
  109. if (isOverlap) {
  110. union_string=std::string(union_r-union_l, 'a');
  111. union_string.replace(L-union_l, R-L, true_data);
  112. union_string.replace(first_zone.first-union_l, first_zone.second.size(), first_zone.second);
  113. if (y>x) {
  114. union_string.replace(last_zone.first-union_l, last_zone.second.size(), last_zone.second);
  115. }
  116. } else {
  117. union_l=L;
  118. union_r=R;
  119. union_string=true_data;
  120. }
  121. if (isOverlap) {
  122. iter = _unassembled_strings.begin();
  123. loc=0;
  124. while (iter!=_unassembled_strings.end()) {
  125. if (loc>=x&&loc<=y) {
  126. _unassembled_strings.erase(iter++);
  127. } else {
  128. iter++;
  129. }
  130. loc++;
  131. }
  132. }
  133. std::cout<<"【"<<union_l<<","<<union_r<<"】"<<"******"<<std::endl;
  134. _unassembled_strings.insert(map<size_t, std::string>::value_type(union_l, union_string));
  135. }
  136. // 接下来比较_next_index和Map中的最小序号
  137. int toDeleteCount=0;
  138. auto iter = _unassembled_strings.begin();
  139. while (iter!=_unassembled_strings.end()) {
  140. if (iter->first!=_next_index) {
  141. break;
  142. }
  143. toDeleteCount++;
  144. // 一定可以全部写入吧???因为前面计算过了
  145. _output.write(iter->second);
  146. // string toAddStr = iter->second;
  147. // size_t added = 0;
  148. // while (added<iter->second.size()) {
  149. // added+=_output.write(iter->second.substr(added, iter->second.size()-added));
  150. // }
  151. _next_index+=iter->second.size();
  152. iter++;
  153. }
  154. iter = _unassembled_strings.begin();
  155. for (int i=0; i<toDeleteCount; i++) {
  156. _unassembled_strings.erase(iter++);
  157. }
  158. if (_unassembled_strings.size()==0&&_next_index==_eof_index) {
  159. _output.end_input();
  160. std::cout<<"****** called _output.end_input(), unassembled_bytes(): "<<unassembled_bytes()<<std::endl;
  161. // std::cout<<"****** _output.eof(): "<<_output.eof()<<std::endl;
  162. // std::cout<<"****** empty(): "<<empty()<<std::endl;
  163. std::cout<<"****** _output.input_ended(): "<<_output.input_ended()<<std::endl;
  164. }
  165. std::cout<<"****** new _next_index: "<<_next_index<<std::endl;
  166. std::cout<<"****** remaining: "<<_output.remaining_capacity()<<std::endl;
  167. // std::cout<<"****** _output.read(): "<<_output.peek_output(8)<<std::endl;
  168. // std::cout<<"****** _output"
  169. }
  170. // 返回已经缓存,但未组装到字节流中的字节个数
  171. size_t StreamReassembler::unassembled_bytes() const {
  172. size_t res=0;
  173. // for (size_t i=0; i<_unassembled_strings.size(); i++) {
  174. // res+=_unassembled_strings[i].second.size();
  175. // }
  176. auto iter = _unassembled_strings.begin();
  177. while (iter!=_unassembled_strings.end()) {
  178. res+=iter->second.size();
  179. iter++;
  180. }
  181. return res;
  182. }
  183. // unassembled_bytes()==0
  184. bool StreamReassembler::empty() const {
  185. return unassembled_bytes()==0;
  186. }

image.png

第四阶段

  • 在刚开始写Lab2时,发现TCPReceiver需要用到我在StreamReassembler中设置的私有变量_next_index
  • 但是实验文档强调了不能修改公有接口,所以我开始思考StreamReassembler中是否有必要设置_next_index这个私有成员变量
  • 实际上,ByteStream有一个接口是size_t bytes_written() const;
    • 这个接口返回了流中写入了多少数据,实际上就是流的下一个字节序号
    • 也就是我一开始设置的_next_index
  • 所以我打算去掉_next_index,为了使改动最小化,我将类成员_next_index改为next_index,即去掉了前面的下划线

    • 类的方法中没有一处用到了next_index
    • 在StreamReassembler::push_substring的开头,定义局部变量_next_index,取值为_output.bytes_written()
  • 潜在的问题:在StreamReassembler::push_substring的最后,我假设_output.write一定会成功,且一定能够把所有字节加进去 ```cpp

    ifndef SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH

    define SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH

include “byte_stream.hh”

include

include

include

include

//! \brief A class that assembles a series of excerpts from a byte stream (possibly out of order, //! possibly overlapping) into an in-order byte stream. class StreamReassembler { private: // Your code here — add private members as necessary. size_t next_index; size_t _eof_index; std::map _unassembled_strings; size_t _unassembled_bytes;

  1. ByteStream _output; //!< The reassembled in-order byte stream
  2. size_t _capacity; //!< The maximum number of bytes

public: //! \brief Construct a StreamReassembler that will store up to capacity bytes. //! \note This capacity limits both the bytes that have been reassembled, //! and those that have not yet been reassembled. StreamReassembler(const size_t capacity);

  1. //! \brief Receive a substring and write any newly contiguous bytes into the stream.
  2. //!
  3. //! The StreamReassembler will stay within the memory limits of the `capacity`.
  4. //! Bytes that would exceed the capacity are silently discarded.
  5. //!
  6. //! \param data the substring
  7. //! \param index indicates the index (place in sequence) of the first byte in `data`
  8. //! \param eof the last byte of `data` will be the last byte in the entire stream
  9. void push_substring(const std::string &data, const uint64_t index, const bool eof);
  10. //! \name Access the reassembled byte stream
  11. //!@{
  12. const ByteStream &stream_out() const { return _output; }
  13. ByteStream &stream_out() { return _output; }
  14. //!@}
  15. //! The number of bytes in the substrings stored but not yet reassembled
  16. //!
  17. //! \note If the byte at a particular index has been pushed more than once, it
  18. //! should only be counted once for the purpose of this function.
  19. size_t unassembled_bytes() const;
  20. //! \brief Is the internal state empty (other than the output stream)?
  21. //! \returns `true` if no substrings are waiting to be assembled
  22. bool empty() const;

};

endif // SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH

include “stream_reassembler.hh”

include

include

include

include

include

include

// Dummy implementation of a stream reassembler.

// For Lab 1, please replace with a real implementation that passes the // automated checks run by make check_lab1.

// You will need to add private members to the class declaration in stream_reassembler.hh

template void DUMMY_CODE(Targs &&… / unused /) {}

using namespace std;

StreamReassembler::StreamReassembler(const size_t capacity) : next_index(0), _eof_index(unsigned(-1)), _unassembled_strings(), _unassembled_bytes(0), _output(capacity), _capacity(capacity) {

}

//! \details This function accepts a substring (aka a segment) of bytes, //! possibly out-of-order, from the logical stream, and assembles any newly //! contiguous substrings and writes them into the output stream in order. void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof) { if (eof) { _eof_index = index+data.size(); }

  1. size_t _next_index=_output.bytes_written();
  2. // [index, index+string.size())
  3. // [_next_index, _next_index+capacity-stream.size())=[_next_index, _next_index+_output.remaining_capacity())
  4. if (index+data.size()>_next_index&&_next_index+_output.remaining_capacity()>index) { // 有相交的部分,或者说有可以缓存的数据
  5. size_t L = std::max(index, _next_index);
  6. size_t R = std::min(index+data.size(), _next_index+_output.remaining_capacity());
  7. std::string true_data=data.substr(L-index, R-L);
  8. size_t x=0,y=0; // 表示了Map中待删除的区间
  9. size_t union_l=0, union_r=0;
  10. bool isOverlap=false;
  11. auto iter = _unassembled_strings.begin();
  12. size_t loc=0;
  13. std::pair<size_t, std::string> first_zone, last_zone;
  14. // std::vector<std::pair<size_t, std::string>> overlapped_strings;
  15. while (iter!=_unassembled_strings.end()) {
  16. // [L, R)和[iter->first, iter->first+iter.second.size())比较
  17. if (iter->first+iter->second.size()>L&&R>iter->first) { // 相交
  18. if (!isOverlap) {
  19. isOverlap = true;
  20. x=y=loc;
  21. first_zone=make_pair(iter->first, iter->second);
  22. union_l=std::min(L, iter->first);
  23. union_r=std::max(R, iter->first+iter->second.size());
  24. } else {
  25. y++;
  26. last_zone=make_pair(iter->first, iter->second);
  27. union_r=std::max(R, iter->first+iter->second.size());
  28. }
  29. } else {
  30. if (isOverlap) {
  31. break;
  32. }
  33. }
  34. loc++;
  35. iter++;
  36. }
  37. std::string union_string;
  38. if (isOverlap) {
  39. union_string=std::string(union_r-union_l, 'a');
  40. union_string.replace(L-union_l, R-L, true_data);
  41. union_string.replace(first_zone.first-union_l, first_zone.second.size(), first_zone.second);
  42. if (y>x) {
  43. union_string.replace(last_zone.first-union_l, last_zone.second.size(), last_zone.second);
  44. }
  45. } else {
  46. union_l=L;
  47. union_r=R;
  48. union_string=true_data;
  49. }
  50. if (isOverlap) {
  51. iter = _unassembled_strings.begin();
  52. loc=0;
  53. while (iter!=_unassembled_strings.end()) {
  54. if (loc>=x&&loc<=y) {
  55. _unassembled_strings.erase(iter++);
  56. } else {
  57. iter++;
  58. }
  59. loc++;
  60. }
  61. }
  62. // std::cout<<"【"<<union_l<<","<<union_r<<"】"<<"******"<<std::endl;
  63. _unassembled_strings.insert(map<size_t, std::string>::value_type(union_l, union_string));
  64. }
  65. // 接下来比较_next_index和Map中的最小序号
  66. int toDeleteCount=0;
  67. auto iter = _unassembled_strings.begin();
  68. while (iter!=_unassembled_strings.end()) {
  69. if (iter->first!=_next_index) {
  70. break;
  71. }
  72. toDeleteCount++;
  73. // 一定可以全部写入吧???因为前面计算过了
  74. _output.write(iter->second);
  75. // string toAddStr = iter->second;
  76. // size_t added = 0;
  77. // while (added<iter->second.size()) {
  78. // added+=_output.write(iter->second.substr(added, iter->second.size()-added));
  79. // }
  80. _next_index+=iter->second.size();
  81. iter++;
  82. }
  83. iter = _unassembled_strings.begin();
  84. for (int i=0; i<toDeleteCount; i++) {
  85. _unassembled_strings.erase(iter++);
  86. }
  87. if (_unassembled_strings.size()==0&&_next_index==_eof_index) {
  88. _output.end_input();
  89. // std::cout<<"****** called _output.end_input(), unassembled_bytes(): "<<unassembled_bytes()<<std::endl;
  90. // std::cout<<"****** _output.eof(): "<<_output.eof()<<std::endl;
  91. // std::cout<<"****** empty(): "<<empty()<<std::endl;
  92. // std::cout<<"****** _output.input_ended(): "<<_output.input_ended()<<std::endl;
  93. }
  94. // std::cout<<"****** new _next_index: "<<_next_index<<std::endl;
  95. // std::cout<<"****** remaining: "<<_output.remaining_capacity()<<std::endl;
  96. // std::cout<<"****** _output.read(): "<<_output.peek_output(8)<<std::endl;
  97. // std::cout<<"****** _output"

}

// 返回已经缓存,但未组装到字节流中的字节个数 size_t StreamReassembler::unassembled_bytes() const { size_t res=0; // for (size_t i=0; i<_unassembled_strings.size(); i++) { // res+=_unassembled_strings[i].second.size(); // } auto iter = _unassembled_strings.begin(); while (iter!=_unassembled_strings.end()) { res+=iter->second.size(); iter++; } return res; }

// unassembled_bytes()==0 bool StreamReassembler::empty() const { return unassembled_bytes()==0; }

  1. <a name="ydbF6"></a>
  2. # 第五阶段
  3. - 引入Lab4的代码后,新增了测试,Lab1又有样例没过,经过DEBUG,发现是我对空串的处理没有做好。
  4. - 如果push_strings传入的是一个空串,我可能会把空串放入**_unassembled_strings**这个Map中,然后就一直留在Map中了。
  5. - 需要修改的地方有两处,一个是判断data.size()>0,才进行把它加入**_unassembled_strings**的操作。
  6. - 由于可能传入一个带着eof标志的空串,所以当前这次操作可能只是更新eof
  7. - 更新了eof,可能整个流的组装就结束了,所以最后的代码逻辑也需要运行
  8. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/3018011/1614809806850-de75ef8b-5108-4b1f-931d-59f0ba1c274a.png#align=left&display=inline&height=467&margin=%5Bobject%20Object%5D&name=image.png&originHeight=467&originWidth=1196&size=113545&status=done&style=none&width=1196)
  9. - 修改了最后调用_output.end_input()的判断条件
  10. - 之前是`_unassembled_strings.size()==0`,这个条件不精确
  11. - 应该改成`unassembled_bytes()==0`
  12. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/3018011/1614809890272-7fd566b1-0a6e-42d5-986b-2a1cde6ba3f9.png#align=left&display=inline&height=311&margin=%5Bobject%20Object%5D&name=image.png&originHeight=311&originWidth=1162&size=77863&status=done&style=none&width=1162)
  13. 下面是修改后的代码
  14. ```cpp
  15. #ifndef SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  16. #define SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  17. #include "byte_stream.hh"
  18. #include <cstdint>
  19. #include <string>
  20. #include <map>
  21. #include <utility>
  22. //! \brief A class that assembles a series of excerpts from a byte stream (possibly out of order,
  23. //! possibly overlapping) into an in-order byte stream.
  24. class StreamReassembler {
  25. private:
  26. // Your code here -- add private members as necessary.
  27. size_t next_index;
  28. size_t _eof_index;
  29. std::map<size_t, std::string> _unassembled_strings;
  30. size_t _unassembled_bytes;
  31. ByteStream _output; //!< The reassembled in-order byte stream
  32. size_t _capacity; //!< The maximum number of bytes
  33. public:
  34. //! \brief Construct a `StreamReassembler` that will store up to `capacity` bytes.
  35. //! \note This capacity limits both the bytes that have been reassembled,
  36. //! and those that have not yet been reassembled.
  37. StreamReassembler(const size_t capacity);
  38. //! \brief Receive a substring and write any newly contiguous bytes into the stream.
  39. //!
  40. //! The StreamReassembler will stay within the memory limits of the `capacity`.
  41. //! Bytes that would exceed the capacity are silently discarded.
  42. //!
  43. //! \param data the substring
  44. //! \param index indicates the index (place in sequence) of the first byte in `data`
  45. //! \param eof the last byte of `data` will be the last byte in the entire stream
  46. void push_substring(const std::string &data, const uint64_t index, const bool eof);
  47. //! \name Access the reassembled byte stream
  48. //!@{
  49. const ByteStream &stream_out() const { return _output; }
  50. ByteStream &stream_out() { return _output; }
  51. //!@}
  52. //! The number of bytes in the substrings stored but not yet reassembled
  53. //!
  54. //! \note If the byte at a particular index has been pushed more than once, it
  55. //! should only be counted once for the purpose of this function.
  56. size_t unassembled_bytes() const;
  57. //! \brief Is the internal state empty (other than the output stream)?
  58. //! \returns `true` if no substrings are waiting to be assembled
  59. bool empty() const;
  60. };
  61. #endif // SPONGE_LIBSPONGE_STREAM_REASSEMBLER_HH
  62. #include "stream_reassembler.hh"
  63. #include <cmath>
  64. #include <vector>
  65. #include <utility>
  66. #include <algorithm>
  67. #include <cstdio>
  68. #include <iostream>
  69. // Dummy implementation of a stream reassembler.
  70. // For Lab 1, please replace with a real implementation that passes the
  71. // automated checks run by `make check_lab1`.
  72. // You will need to add private members to the class declaration in `stream_reassembler.hh`
  73. template <typename... Targs>
  74. void DUMMY_CODE(Targs &&... /* unused */) {}
  75. using namespace std;
  76. StreamReassembler::StreamReassembler(const size_t capacity)
  77. : next_index(0), _eof_index(unsigned(-1)), _unassembled_strings(), _unassembled_bytes(0),
  78. _output(capacity), _capacity(capacity) {
  79. std::cout<<"****** StreamReassembler created"<<std::endl;
  80. }
  81. //! \details This function accepts a substring (aka a segment) of bytes,
  82. //! possibly out-of-order, from the logical stream, and assembles any newly
  83. //! contiguous substrings and writes them into the output stream in order.
  84. void StreamReassembler::push_substring(const string &data, const size_t index, const bool eof) {
  85. if (eof) {
  86. _eof_index = index+data.size();
  87. std::cout<<"****** get _eof_index: "<<_eof_index<<std::endl;
  88. }
  89. std::cout<<"****** try to push string: "<<data;
  90. size_t _next_index=_output.bytes_written();
  91. std::cout<<", get _next_index this time: "<<_next_index;
  92. // [index, index+string.size())
  93. // [_next_index, _next_index+capacity-stream.size())=[_next_index, _next_index+_output.remaining_capacity())
  94. // 不能加入空串,加入data.size()>0的判断,因为可能来一个空串,并且更新eof,所以不能直接返回,后面的代码还要运行
  95. if (data.size()>0&&index+data.size()>_next_index&&_next_index+_output.remaining_capacity()>index) { // 有相交的部分,或者说有可以缓存的数据
  96. size_t L = std::max(index, _next_index);
  97. size_t R = std::min(index+data.size(), _next_index+_output.remaining_capacity());
  98. std::string true_data=data.substr(L-index, R-L);
  99. std::cout<<", pushed: "<<true_data;
  100. size_t x=0,y=0; // 表示了Map中待删除的区间
  101. size_t union_l=0, union_r=0;
  102. bool isOverlap=false;
  103. auto iter = _unassembled_strings.begin();
  104. size_t loc=0;
  105. std::pair<size_t, std::string> first_zone, last_zone;
  106. // std::vector<std::pair<size_t, std::string>> overlapped_strings;
  107. while (iter!=_unassembled_strings.end()) {
  108. // [L, R)和[iter->first, iter->first+iter.second.size())比较
  109. if (iter->first+iter->second.size()>L&&R>iter->first) { // 相交
  110. if (!isOverlap) {
  111. isOverlap = true;
  112. x=y=loc;
  113. first_zone=make_pair(iter->first, iter->second);
  114. union_l=std::min(L, iter->first);
  115. union_r=std::max(R, iter->first+iter->second.size());
  116. } else {
  117. y++;
  118. last_zone=make_pair(iter->first, iter->second);
  119. union_r=std::max(R, iter->first+iter->second.size());
  120. }
  121. } else {
  122. if (isOverlap) {
  123. break;
  124. }
  125. }
  126. loc++;
  127. iter++;
  128. }
  129. std::string union_string;
  130. if (isOverlap) {
  131. union_string=std::string(union_r-union_l, 'a');
  132. union_string.replace(L-union_l, R-L, true_data);
  133. union_string.replace(first_zone.first-union_l, first_zone.second.size(), first_zone.second);
  134. if (y>x) {
  135. union_string.replace(last_zone.first-union_l, last_zone.second.size(), last_zone.second);
  136. }
  137. } else {
  138. union_l=L;
  139. union_r=R;
  140. union_string=true_data;
  141. }
  142. if (isOverlap) {
  143. iter = _unassembled_strings.begin();
  144. loc=0;
  145. while (iter!=_unassembled_strings.end()) {
  146. if (loc>=x&&loc<=y) {
  147. _unassembled_strings.erase(iter++);
  148. } else {
  149. iter++;
  150. }
  151. loc++;
  152. }
  153. }
  154. // std::cout<<"【"<<union_l<<","<<union_r<<"】"<<"******"<<std::endl;
  155. _unassembled_strings.insert(map<size_t, std::string>::value_type(union_l, union_string));
  156. }
  157. // 接下来比较_next_index和Map中的最小序号
  158. int toDeleteCount=0;
  159. auto iter = _unassembled_strings.begin();
  160. while (iter!=_unassembled_strings.end()) {
  161. if (iter->first!=_next_index) {
  162. break;
  163. }
  164. toDeleteCount++;
  165. // 一定可以全部写入吧???因为前面计算过了
  166. _output.write(iter->second);
  167. // string toAddStr = iter->second;
  168. // size_t added = 0;
  169. // while (added<iter->second.size()) {
  170. // added+=_output.write(iter->second.substr(added, iter->second.size()-added));
  171. // }
  172. _next_index+=iter->second.size();
  173. iter++;
  174. }
  175. iter = _unassembled_strings.begin();
  176. for (int i=0; i<toDeleteCount; i++) {
  177. _unassembled_strings.erase(iter++);
  178. }
  179. std::cout<<", buffer size now: "<<_output.buffer_size();
  180. std::cout<<", _next_index now: "<<_next_index;
  181. std::cout<<", unassembled_bytes now: "<<unassembled_bytes();
  182. std::cout<<", _unassembled_strings.size(): "<<_unassembled_strings.size()<<std::endl;
  183. // if (_unassembled_strings.size()==0&&_next_index==_eof_index) {
  184. if (unassembled_bytes()==0&&_next_index==_eof_index) {
  185. _output.end_input();
  186. std::cout<<"****** called _output.end_input(), unassembled_bytes(): "<<unassembled_bytes();
  187. std::cout<<" _output.buffer_size(): "<<_output.buffer_size()<<std::endl;
  188. // std::cout<<"****** _output.eof(): "<<_output.eof()<<std::endl;
  189. // std::cout<<"****** empty(): "<<empty()<<std::endl;
  190. // std::cout<<"****** _output.input_ended(): "<<_output.input_ended()<<std::endl;
  191. // std::cout<<"****** _output.peek_output(8): "<<_output.peek_output(8)<<std::endl;
  192. }
  193. // std::cout<<"****** new _next_index: "<<_next_index<<std::endl;
  194. // std::cout<<"****** remaining: "<<_output.remaining_capacity()<<std::endl;
  195. // std::cout<<"****** _output.read(): "<<_output.peek_output(8)<<std::endl;
  196. // std::cout<<"****** _output"
  197. }
  198. // 返回已经缓存,但未组装到字节流中的字节个数
  199. size_t StreamReassembler::unassembled_bytes() const {
  200. size_t res=0;
  201. // for (size_t i=0; i<_unassembled_strings.size(); i++) {
  202. // res+=_unassembled_strings[i].second.size();
  203. // }
  204. auto iter = _unassembled_strings.begin();
  205. while (iter!=_unassembled_strings.end()) {
  206. res+=iter->second.size();
  207. iter++;
  208. }
  209. return res;
  210. }
  211. // unassembled_bytes()==0
  212. bool StreamReassembler::empty() const {
  213. return unassembled_bytes()==0;
  214. }