diff options
Diffstat (limited to 'distbuild/stringbuffer.py')
-rw-r--r-- | distbuild/stringbuffer.py | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/distbuild/stringbuffer.py b/distbuild/stringbuffer.py new file mode 100644 index 00000000..3349bb87 --- /dev/null +++ b/distbuild/stringbuffer.py @@ -0,0 +1,90 @@ +# mainloop/stringbuffer.py -- efficient buffering of strings as a queue +# +# Copyright 2012 Codethink Limited +# All rights reserved. + + +class StringBuffer(object): + + '''Buffer data for a file descriptor. + + The data may arrive in small pieces, and it is buffered in a way that + avoids excessive string catenation or splitting. + + ''' + + def __init__(self): + self.strings = [] + self.len = 0 + + def add(self, data): + '''Add data to buffer.''' + self.strings.append(data) + self.len += len(data) + + def remove(self, num_bytes): + '''Remove specified number of bytes from buffer.''' + while num_bytes > 0 and self.strings: + first = self.strings[0] + if len(first) <= num_bytes: + num_bytes -= len(first) + del self.strings[0] + self.len -= len(first) + else: + self.strings[0] = first[num_bytes:] + self.len -= num_bytes + num_bytes = 0 + + def peek(self): + '''Return contents of buffer as one string.''' + + if len(self.strings) == 0: + return '' + elif len(self.strings) == 1: + return self.strings[0] + else: + self.strings = [''.join(self.strings)] + return self.strings[0] + + def read(self, max_bytes): + '''Return up to max_bytes from the buffer. + + Less is returned if the buffer does not contain at least max_bytes. + The returned data will remain in the buffer; use remove to remove + it. + + ''' + + use = [] + size = 0 + for s in self.strings: + n = max_bytes - size + if len(s) <= n: + use.append(s) + size += len(s) + else: + use.append(s[:n]) + size += n + break + return ''.join(use) + + def readline(self): + '''Return a complete line (ends with '\n') or None.''' + + for i, s in enumerate(self.strings): + newline = s.find('\n') + if newline != -1: + if newline+1 == len(s): + use = self.strings[:i+1] + del self.strings[:i+1] + else: + pre = s[:newline+1] + use = self.strings[:i] + [pre] + del self.strings[:i] + self.strings[0] = s[newline+1:] + return ''.join(use) + return None + + def __len__(self): + return self.len + |