#include #include #include #include #include "buffer.hpp" namespace distribnet { using namespace std; void Buffer::reset() { if (own() && capacity_) delete[] storage_begin(); begin_ = end_ = 0; storage_end_ = 0; capacity_ = 0; } void Buffer::swap(Buffer & other) { std::swap(begin_, other.begin_); std::swap(end_, other.end_); std::swap(storage_end_, other.storage_end_); std::swap(capacity_, other.capacity_); } void Buffer::assign(const Buffer & other) { size_type other_size = other.size(); assert(other_size <= max_size()); if (capacity() < other_size) { delete[] storage_begin(); begin_ = new byte[other_size]; storage_end_ = begin_ + other_size; capacity_ = other_size; } begin_ = storage_begin(); memcpy(begin_, other.begin_, other_size); end_ = begin_ + other_size; } Buffer::Buffer(const Buffer & other) { size_type other_size = other.size(); begin_ = new byte[other_size]; storage_end_ = begin_ + other_size; capacity_ = other_size; memcpy(begin_, other.begin_, other_size); end_ = begin_ + other_size; } void Buffer::set(byte * new_begin, byte * new_end) { if (own() && capacity_) delete[] storage_begin(); begin_ = new_begin; end_ = new_end; capacity_ = new_end - new_begin; storage_end_ = new_end; own(false); } void Buffer::set_storage(byte * new_begin, byte * new_end) { if (own() && capacity_) delete[] storage_begin(); capacity_ = new_end - new_begin; storage_end_ = new_end; begin_ = new_begin; end_ = begin_; own(false); } void Buffer::align_front() { if (storage_begin() != begin_) { size_type s = size(); if (s) memmove(storage_begin(), begin_, s); begin_ = storage_begin(); end_ = begin_ + s; } } void Buffer::align_back() { if (storage_end() != end_) { size_type s = size(); if (s) memmove(storage_end() - s, begin_, s); begin_ = storage_end() - s; end_ = begin_ + s; } } void Buffer::resize(size_type s) { assert(s <= max_size()); if (s > capacity()) { reserve(s); } else if (begin_ + s > storage_end()) { memmove(storage_begin(), begin_, size()); begin_ = storage_begin(); } end_ = begin_ + s; } void Buffer::reserve(size_type s) { assert(s <= max_size()); if (s > capacity()) { size_type old_size = size(); byte * new_block = new byte[s]; if (!empty()) memcpy(new_block, begin_, old_size); if (capacity_) delete[] storage_begin(); capacity_ = s; begin_ = new_block; end_ = begin_ + old_size; storage_end_ = new_block + s; } } void Buffer::reserve_towards_back(size_type s) { assert(s <= max_size()); if (s > capacity()) { size_type old_size = size(); size_type diff = s - old_size; byte * new_block = new byte[s]; if (!empty()) memcpy(new_block + diff, begin_, old_size); if (capacity_) delete[] storage_begin(); capacity_ = s; begin_ = new_block + diff; end_ = begin_ + old_size; storage_end_ = new_block + s; } else { align_back(); } } bool Buffer::shrink() { size_type s = size(); if (s == capacity()) return true; if (!own()) return false; byte * new_block = new byte[s]; memcpy(new_block, begin_, s); begin_ = new_block; end_ = new_block + s; capacity_ = s; storage_end_ = end_; return true; } void Buffer::adj_range(byte * start, byte * stop, size_type intv_size) { assert(begin_ <= start && start <= stop && stop <= end_); difference_type diff = intv_size - (stop - start); if (diff == 0) return; size_type beg_size = start - begin_; size_type end_size = end_ - stop; size_type new_size = size() + diff; assert(new_size <= max_size()); if (diff < 0) { if (beg_size == 0) { begin_ -= diff; } else if (end_size == 0) { end_ += diff; } else { if (beg_size < end_size) { memmove(begin_ - diff, begin_, beg_size); begin_ -= diff; } else { memmove(stop + diff, stop, end_size); end_ += diff; } } } else // diff > 0 { if (size() + diff <= capacity()) { difference_type beg_buf = begin_ - storage_begin(); difference_type end_buf = storage_end() - end_; // Possibilities // b/e b e action possibilities // ------------------------ // x F F << 4 // B F T << 1 // E T F << 1 // B T x B 2 // E x T E 2 // M T F B 2 // < T T B 1 // M F T E 2 // > T T E 1 // ------------------- 16 // b/e: Insert in Beginning/Middle/End // <,>: Beginning Part ? Ending Part (Middle = <|>) // b: Beggining buffer > size diffrence // e: Ending buffer > size diffrence // action: <<: Move Beg Part to Beg of storage, Move End as needed // B: Move Beg Part Needed amount // E: Move End Part Needed amount if ((beg_buf < diff && end_buf < diff) || (beg_size == 0 && beg_buf < diff) || (end_size == 0 && end_buf < diff)) { if (beg_size) memmove(storage_begin(), begin_, beg_size); diff -= beg_size; if (end_size) memmove(stop + diff, stop, end_size); begin_ = storage_begin(); end_ = begin_ + new_size; } else if (beg_size == 0) { begin_ -= diff; } else if (end_size == 0) { end_ += diff; } else if (diff <= beg_buf && (end_buf < diff || beg_size < end_size)) { memmove(begin_ - diff, begin_, beg_size); begin_ = begin_ - diff; } else if (diff <= end_buf && (beg_buf < diff || beg_size >= end_size)) { memmove(stop + diff, stop, end_size); end_ += diff; } else { abort(); // this should never happen } } else // size() + diff > capacity { size_type alloc_size = size() * 2; if (alloc_size < 16) alloc_size = 16; if (alloc_size < new_size) alloc_size = new_size; byte * new_block = new byte[alloc_size]; if (beg_size) memcpy(new_block, begin_, beg_size); if (end_size) memcpy(new_block + beg_size + intv_size, stop, end_size); delete[] storage_begin(); capacity_ = alloc_size; begin_ = new_block; end_ = begin_ + new_size; storage_end_ = new_block + alloc_size; } } } } #include using namespace std; using namespace distribnet; void print_buffer(Buffer & buf) { cout << "S=" << buf.size() << " " << "C=" << buf.capacity() << " " << "M=" << buf.max_size() << " " << "D="; for (size_t i = 0; i != buf.size(); ++i) cout.put(buf[i]); cout << endl; } int main() { Buffer buf, buf2; for (int i = 0; i != 10; ++i) { buf.push_back('a'); } print_buffer(buf); buf.swap(buf2); print_buffer(buf); print_buffer(buf2); buf.reset(); print_buffer(buf); buf.alloc(10); memcpy(buf.data(), "0123456789", 10); print_buffer(buf); int pos = buf.alloc(6); print_buffer(buf); memcpy(buf.data(pos), "ABCDEF", 6); print_buffer(buf); buf.append("!!!", 3); buf.prepend("!!!", 3); print_buffer(buf); buf.insert(3, "....", 4); buf.insert(12, "....", 4); print_buffer(buf); buf.replace(3, 4, "abcdef", 6); print_buffer(buf); buf.pop_front(3); buf.replace(6, 0, "...", 3); print_buffer(buf); buf.replace(6, 3, "??????", 6); print_buffer(buf); buf2 = buf; print_buffer(buf2); buf.shrink(); print_buffer(buf); }