diff options
Diffstat (limited to 'src/base/circlebuf.cc')
-rw-r--r-- | src/base/circlebuf.cc | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc new file mode 100644 index 000000000..a0c015671 --- /dev/null +++ b/src/base/circlebuf.cc @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2002-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Nathan Binkert + */ + +#include <algorithm> +#include <string> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "base/circlebuf.hh" +#include "base/cprintf.hh" +#include "base/intmath.hh" + +using namespace std; + +CircleBuf::CircleBuf(int l) + : _rollover(false), _buflen(l), _size(0), _start(0), _stop(0) +{ + _buf = new char[_buflen]; +} + +CircleBuf::~CircleBuf() +{ + if (_buf) + delete [] _buf; +} + +void +CircleBuf::dump() +{ + cprintf("start = %10d, stop = %10d, buflen = %10d\n", + _start, _stop, _buflen); + fflush(stdout); + ::write(STDOUT_FILENO, _buf, _buflen); + ::write(STDOUT_FILENO, "<\n", 2); +} + +void +CircleBuf::flush() +{ + _start = 0; + _stop = 0; + _rollover = false; +} + +void +CircleBuf::read(char *b, int len) +{ + _size -= len; + if (_size < 0) + _size = 0; + + if (_stop > _start) { + len = min(len, _stop - _start); + memcpy(b, _buf + _start, len); + _start += len; + } + else { + int endlen = _buflen - _start; + if (endlen > len) { + memcpy(b, _buf + _start, len); + _start += len; + } + else { + memcpy(b, _buf + _start, endlen); + _start = min(len - endlen, _stop); + memcpy(b + endlen, _buf, _start); + } + } +} + +void +CircleBuf::read(int fd, int len) +{ + _size -= len; + if (_size < 0) + _size = 0; + + if (_stop > _start) { + len = min(len, _stop - _start); + ::write(fd, _buf + _start, len); + _start += len; + } + else { + int endlen = _buflen - _start; + if (endlen > len) { + ::write(fd, _buf + _start, len); + _start += len; + } + else { + ::write(fd, _buf + _start, endlen); + _start = min(len - endlen, _stop); + ::write(fd, _buf, _start); + } + } +} + +void +CircleBuf::read(int fd) +{ + _size = 0; + + if (_stop > _start) { + ::write(fd, _buf + _start, _stop - _start); + } + else { + ::write(fd, _buf + _start, _buflen - _start); + ::write(fd, _buf, _stop); + } + + _start = _stop; +} + +void +CircleBuf::read(ostream &out) +{ + _size = 0; + + if (_stop > _start) { + out.write(_buf + _start, _stop - _start); + } + else { + out.write(_buf + _start, _buflen - _start); + out.write(_buf, _stop); + } + + _start = _stop; +} + +void +CircleBuf::readall(int fd) +{ + if (_rollover) + ::write(fd, _buf + _stop, _buflen - _stop); + + ::write(fd, _buf, _stop); + _start = _stop; +} + +void +CircleBuf::write(char b) +{ + write(&b, 1); +} + +void +CircleBuf::write(const char *b) +{ + write(b, strlen(b)); +} + +void +CircleBuf::write(const char *b, int len) +{ + if (len <= 0) + return; + + _size += len; + if (_size > _buflen) + _size = _buflen; + + int old_start = _start; + int old_stop = _stop; + + if (len >= _buflen) { + _start = 0; + _stop = _buflen; + _rollover = true; + memcpy(_buf, b + (len - _buflen), _buflen); + return; + } + + if (_stop + len <= _buflen) { + memcpy(_buf + _stop, b, len); + _stop += len; + } else { + int end_len = _buflen - old_stop; + _stop = len - end_len; + memcpy(_buf + old_stop, b, end_len); + memcpy(_buf, b + end_len, _stop); + _rollover = true; + } + + if (old_start > old_stop && old_start < _stop || + old_start < old_stop && _stop < old_stop) + _start = _stop + 1; +} |