//! \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. classStreamReassembler { private: // Your code here -- add private members as necessary.
ByteStream _output; //!< The reassembled in-order byte stream size_t _capacity; //!< The maximum number of bytes size_t _first_uass; // index of segment waiting for size_t _unassembled_bytes; bool _eof; // whether _eof_ is effecitve size_t _eof_idx; // where the eof is std::set<StreamBlock> _blocks;
//! Merge the two blocks "blk" and "new_block" //! the result will stored in new_block //! nothing happens if two blocks can't merge //! return ture if merge happens, false otherwise
//! add "to_add" blocks to set blocks //! merge all the blocks mergeable inlinevoidadd_block(StreamBlock &new_block);
//! Write the first block to the stream, this block should begin at '_first_uass' inlinevoidwrite_to_stream();
//! Check if eof is written to the stream //! If true, end the stream inlinevoidEOFcheck();
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(constsize_t capacity);
//! \brief Receive a substring and write any newly contiguous bytes into the stream. //! //! The StreamReassembler will stay within the memory limits of the `capacity`. //! Bytes that would exceed the capacity are silently discarded. //! //! \param data the substring //! \param index indicates the index (place in sequence) of the first byte in `data` //! \param eof the last byte of `data` will be the last byte in the entire stream voidpush_substring(const std::string &data, constuint64_t index, constbool eof); voidpush_substring(const Buffer &data, constsize_t index, constbool eof);
//! The number of bytes in the substrings stored but not yet reassembled //! //! \note If the byte at a particular index has been pushed more than once, it //! should only be counted once for the purpose of this function. size_tunassembled_bytes()const;
//! \brief Is the internal state empty (other than the output stream)? //! \returns `true` if no substrings are waiting to be assembled boolempty()const; };
//! \details This function check if eof is written to the stream inlinevoidStreamReassembler::EOFcheck(){ if (!_eof) { return; } if (static_cast<size_t>(_eof_idx) == _first_uass) { _output.end_input(); } }
//! \details This function write the first block into the stream, //! the first block should begin at '_first_uass' inlinevoidStreamReassembler::write_to_stream(){ while (!_blocks.empty()) { auto block = *_blocks.begin(); if (block.begin() != _first_uass) { return; }
//! \details This function add "to_add" blocks to set blocks // merge all the blocks mergeable inlinevoidStreamReassembler::add_block(StreamBlock &new_block){ if (new_block.len() == 0) { return; }
//! \details This function check if the two blocks have overlap part boolStreamReassembler::overlap(const StreamBlock &blk, const StreamBlock &new_blk)const{ if (blk.begin() < new_blk.begin()) { return new_blk.begin() < blk.end(); }
//! \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. voidStreamReassembler::push_substring(const string &data, constsize_t index, constbool eof){ // the data that have been reassembled if (index + data.size() < _first_uass) { return; }
if (eof && !_eof) { _eof = true; _eof_idx = index + data.size(); }
StreamBlock blk(index, move(string(data)));
// if a part of the data have been reassembled if (index < _first_uass) { blk.buffer().remove_prefix(_first_uass - index); }
// if a part of the data out of the capacity if (index + data.size() > _capacity + _first_uass) { blk.buffer().remove_suffix(index + data.size() - _capacity - _first_uass); }
//! \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. classStreamReassembler { private: // Your code here -- add private members as necessary.
ByteStream _output; //!< The reassembled in-order byte stream size_t _capacity; //!< The maximum number of bytes size_t _first_uass; // index of segment waiting for size_t _unassembled_bytes; bool _eof; // whether _eof_ is effecitve size_t _eof_idx; // where the eof is std::set<StreamBlock> _blocks;
//! Merge the two blocks "blk" and "new_block" //! the result will stored in new_block //! nothing happens if two blocks can't merge //! return ture if merge happens, false otherwise
//! add "to_add" blocks to set blocks //! merge all the blocks mergeable inlinevoidadd_block(StreamBlock &new_block);
//! Write the first block to the stream, this block should begin at '_first_uass' inlinevoidwrite_to_stream();
//! Check if eof is written to the stream //! If true, end the stream inlinevoidEOFcheck();
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(constsize_t capacity);
//! \brief Receive a substring and write any newly contiguous bytes into the stream. //! //! The StreamReassembler will stay within the memory limits of the `capacity`. //! Bytes that would exceed the capacity are silently discarded. //! //! \param data the substring //! \param index indicates the index (place in sequence) of the first byte in `data` //! \param eof the last byte of `data` will be the last byte in the entire stream voidpush_substring(const std::string &data, constuint64_t index, constbool eof); voidpush_substring(const Buffer &data, constsize_t index, constbool eof);
//! The number of bytes in the substrings stored but not yet reassembled //! //! \note If the byte at a particular index has been pushed more than once, it //! should only be counted once for the purpose of this function. size_tunassembled_bytes()const;
//! \brief Is the internal state empty (other than the output stream)? //! \returns `true` if no substrings are waiting to be assembled boolempty()const; };
//! \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. voidStreamReassembler::push_substring(const string &data, constsize_t index, constbool eof){ // the data that have been reassembled if (index + data.size() < _first_uass) { return; }
if (eof && !_eof) { _eof = true; _eof_idx = index + data.size(); }
StreamBlock blk(index, move(string(data)));
// if a part of the data have been reassembled if (index < _first_uass) { blk.buffer().remove_prefix(_first_uass - index); }
// if a part of the data out of the capacity if (index + data.size() > _capacity + _first_uass) { blk.buffer().remove_suffix(index + data.size() - _capacity - _first_uass); }
add_block(blk); write_to_stream(); EOFcheck(); }
voidStreamReassembler::push_substring(const Buffer &data, constsize_t index, constbool eof){ // the data that have been reassembled if (index + data.size() < _first_uass) { return; }
if (eof && !_eof) { _eof = true; _eof_idx = index + data.size(); }
StreamBlock blk(index, move(data));
// if a part of the data have been reassembled if (index < _first_uass) { blk.buffer().remove_prefix(_first_uass - index); }
// if a part of the data out of the capacity if (index + data.size() > _capacity + _first_uass) { blk.buffer().remove_suffix(index + data.size() - _capacity - _first_uass); }
add_block(blk); write_to_stream(); EOFcheck(); }
//! \details This function check if eof is written to the stream inlinevoidStreamReassembler::EOFcheck(){ if (!_eof) { return; } if (static_cast<size_t>(_eof_idx) == _first_uass) { _output.end_input(); } }
//! \details This function write the first block into the stream, //! the first block should begin at '_first_uass' inlinevoidStreamReassembler::write_to_stream(){ while (!_blocks.empty()) { auto block = *_blocks.begin(); if (block.begin() != _first_uass) { return; }
// partially written if (bytes_written != block.len()) { block.buffer().remove_prefix(move(bytes_written)); _blocks.insert(move(block)); } } }
//! \details This function add "to_add" blocks to set blocks // merge all the blocks mergeable inlinevoidStreamReassembler::add_block(StreamBlock &new_block){ if (new_block.len() == 0) { return; }
// compare with prevs // check one previous block is enough if (prev != _blocks.begin()) { prev -- ; nblk = blks_to_add.begin();
if (overlap(*nblk, *prev)) { (*nblk).buffer().remove_prefix((*prev).end() - (*nblk).begin()); } } }
for (auto &blk : blks_to_add) { if (blk.len() != 0) { _blocks.emplace(move(blk)); _unassembled_bytes += blk.len(); } } }
//! \details This function check if the two blocks have overlap part boolStreamReassembler::overlap(const StreamBlock &blk, const StreamBlock &new_blk)const{ if (blk.begin() < new_blk.begin()) { return new_blk.begin() < blk.end(); }